use of com.yahoo.pulsar.client.api.Message in project pulsar by yahoo.
the class MessageIdTest method testCorruptMessageRemove.
/**
* Verifies: if message is corrupted before sending to broker and if broker gives checksum error: then
* 1. Client-Producer recomputes checksum with modified data
* 2. Retry message-send again
* 3. Broker verifies checksum
* 4. client receives send-ack success
*
* @throws Exception
*/
@Test
public void testCorruptMessageRemove() throws Exception {
final String topicName = "persistent://prop/use/ns-abc/retry-topic";
ProducerConfiguration config = new ProducerConfiguration();
config.setSendTimeout(10, TimeUnit.MINUTES);
// 1. producer connect
Producer prod = pulsarClient.createProducer(topicName, config);
ProducerImpl producer = spy((ProducerImpl) prod);
Field producerIdField = ProducerImpl.class.getDeclaredField("producerId");
producerIdField.setAccessible(true);
long producerId = (long) producerIdField.get(producer);
// registered spy ProducerImpl
producer.cnx().registerProducer(producerId, producer);
Consumer consumer = pulsarClient.subscribe(topicName, "my-sub");
// 2. Stop the broker, and publishes messages. Messages are accumulated in the producer queue and they're
// checksums
// would have already been computed. If we change the message content at that point, it should result in a
// checksum validation error
// enable checksum at producer
stopBroker();
Message msg = MessageBuilder.create().setContent("message-1".getBytes()).build();
CompletableFuture<MessageId> future = producer.sendAsync(msg);
// 3. corrupt the message
// new content would be 'message-3'
msg.getData()[msg.getData().length - 1] = '2';
// 4. Restart the broker to have the messages published
startBroker();
try {
future.get();
fail("send message should have failed with checksum excetion");
} catch (Exception e) {
if (e.getCause() instanceof PulsarClientException.ChecksumException) {
//ok (callback should get checksum exception as message was modified and corrupt)
} else {
fail("Callback should have only failed with ChecksumException", e);
}
}
// 5. Verify
// (5.1) Verify: producer's recoverChecksumError and updateChecksum invoked
verify(producer, times(1)).recoverChecksumError(any(), anyLong());
verify(producer, times(1)).verifyLocalBufferIsNotCorrupted(any());
/**
* (5.3) verify: ProducerImpl.verifyLocalBufferIsNotCorrupted() => validates if message
* is corrupt
*/
MessageImpl msg2 = (MessageImpl) MessageBuilder.create().setContent("message-1".getBytes()).build();
ByteBuf payload = msg2.getDataBuffer();
Builder metadataBuilder = ((MessageImpl) msg).getMessageBuilder();
MessageMetadata msgMetadata = metadataBuilder.setProducerName("test").setSequenceId(1).setPublishTime(10L).build();
ByteBuf cmd = Commands.newSend(producerId, 1, 1, ChecksumType.Crc32c, msgMetadata, payload);
// (a) create OpSendMsg with message-data : "message-1"
OpSendMsg op = OpSendMsg.create(((MessageImpl) msg), cmd, 1, null);
// a.verify: as message is not corrupt: no need to update checksum
assertTrue(producer.verifyLocalBufferIsNotCorrupted(op));
// (b) corrupt message
// new content would be 'message-2'
msg2.getData()[msg2.getData().length - 1] = '2';
// b. verify: as message is corrupt: update checksum
assertFalse(producer.verifyLocalBufferIsNotCorrupted(op));
assertEquals(producer.getPendingQueueSize(), 0);
// [2] test-recoverChecksumError functionality
stopBroker();
MessageImpl msg1 = (MessageImpl) MessageBuilder.create().setContent("message-1".getBytes()).build();
future = producer.sendAsync(msg1);
ClientCnx cnx = spy(new ClientCnx((PulsarClientImpl) pulsarClient) {
});
String exc = "broker is already stopped";
// when client-try to recover checksum by resending to broker: throw exception as broker is stopped
doThrow(new IllegalStateException(exc)).when(cnx).ctx();
try {
producer.recoverChecksumError(cnx, 1);
fail("it should call : resendMessages() => which should throw above mocked exception");
} catch (IllegalStateException e) {
assertEquals(exc, e.getMessage());
}
producer.close();
consumer.close();
// clean reference of mocked producer
producer = null;
}
use of com.yahoo.pulsar.client.api.Message in project pulsar by yahoo.
the class PersistentTopicsImpl method peekNthMessage.
private CompletableFuture<Message> peekNthMessage(String destination, String subName, int messagePosition) {
DestinationName ds = validateTopic(destination);
String encodedSubName = Codec.encode(subName);
final CompletableFuture<Message> future = new CompletableFuture<Message>();
asyncGetRequest(persistentTopics.path(ds.getNamespace()).path(ds.getEncodedLocalName()).path("subscription").path(encodedSubName).path("position").path(String.valueOf(messagePosition)), new InvocationCallback<Response>() {
@Override
public void completed(Response response) {
try {
Message msg = getMessageFromHttpResponse(response);
future.complete(msg);
} catch (Exception e) {
future.completeExceptionally(getApiException(e));
}
}
@Override
public void failed(Throwable throwable) {
future.completeExceptionally(getApiException(throwable.getCause()));
}
});
return future;
}
use of com.yahoo.pulsar.client.api.Message in project pulsar by yahoo.
the class CmdConsume method run.
/**
* Run the consume command.
*
* @return 0 for success, < 0 otherwise
*/
public int run() throws PulsarClientException, IOException {
if (mainOptions.size() != 1)
throw (new ParameterException("Please provide one and only one topic name."));
if (this.serviceURL == null || this.serviceURL.isEmpty())
throw (new ParameterException("Broker URL is not provided."));
if (this.subscriptionName == null || this.subscriptionName.isEmpty())
throw (new ParameterException("Subscription name is not provided."));
if (this.numMessagesToConsume < 0)
throw (new ParameterException("Number of messages should be zero or positive."));
String topic = this.mainOptions.get(0);
int numMessagesConsumed = 0;
int returnCode = 0;
try {
ConsumerConfiguration consumerConf = new ConsumerConfiguration();
consumerConf.setSubscriptionType(this.subscriptionType);
PulsarClient client = PulsarClient.create(this.serviceURL, this.clientConfig);
Consumer consumer = client.subscribe(topic, this.subscriptionName, consumerConf);
RateLimiter limiter = (this.consumeRate > 0) ? RateLimiter.create(this.consumeRate) : null;
while (this.numMessagesToConsume == 0 || numMessagesConsumed < this.numMessagesToConsume) {
if (limiter != null) {
limiter.acquire();
}
Message msg = consumer.receive(5, TimeUnit.SECONDS);
if (msg == null) {
LOG.warn("No message to consume after waiting for 20 seconds.");
} else {
numMessagesConsumed += 1;
System.out.println(MESSAGE_BOUNDARY);
String output = this.interpretMessage(msg, displayHex);
System.out.println(output);
consumer.acknowledge(msg);
}
}
client.close();
} catch (Exception e) {
LOG.error("Error while consuming messages");
LOG.error(e.getMessage(), e);
returnCode = -1;
} finally {
LOG.info("{} messages successfully consumed", numMessagesConsumed);
}
return returnCode;
}
use of com.yahoo.pulsar.client.api.Message in project pulsar by yahoo.
the class CmdProduce method run.
/**
* Run the producer.
*
* @return 0 for success, < 0 otherwise
* @throws Exception
*/
public int run() throws PulsarClientException {
if (mainOptions.size() != 1)
throw (new ParameterException("Please provide one and only one topic name."));
if (this.serviceURL == null || this.serviceURL.isEmpty())
throw (new ParameterException("Broker URL is not provided."));
if (this.numTimesProduce <= 0)
throw (new ParameterException("Number of times need to be positive number."));
if (messages.size() == 0 && messageFileNames.size() == 0)
throw (new ParameterException("Please supply message content with either --messages or --files"));
int totalMessages = (messages.size() + messageFileNames.size()) * numTimesProduce;
if (totalMessages > MAX_MESSAGES) {
String msg = "Attempting to send " + totalMessages + " messages. Please do not send more than " + MAX_MESSAGES + " messages";
throw new ParameterException(msg);
}
String topic = this.mainOptions.get(0);
int numMessagesSent = 0;
int returnCode = 0;
try {
PulsarClient client = PulsarClient.create(this.serviceURL, this.clientConfig);
Producer producer = client.createProducer(topic);
List<byte[]> messageBodies = generateMessageBodies(this.messages, this.messageFileNames);
RateLimiter limiter = (this.publishRate > 0) ? RateLimiter.create(this.publishRate) : null;
for (int i = 0; i < this.numTimesProduce; i++) {
List<Message> messages = generateMessages(messageBodies);
for (Message msg : messages) {
if (limiter != null)
limiter.acquire();
producer.send(msg);
numMessagesSent++;
}
}
client.close();
} catch (Exception e) {
LOG.error("Error while producing messages");
LOG.error(e.getMessage(), e);
returnCode = -1;
} finally {
LOG.info("{} messages successfully produced", numMessagesSent);
}
return returnCode;
}
use of com.yahoo.pulsar.client.api.Message in project pulsar by yahoo.
the class CmdProduce method generateMessages.
/*
* Generates a list of messages that can be produced
*
* @param stringMessages List of strings to send as messages
*
* @param messageFileNames List of file names to read and send as messages
*
* @return list of messages to send
*/
private List<Message> generateMessages(List<byte[]> messageBodies) {
List<Message> messagesToSend = new ArrayList<Message>();
try {
for (byte[] msgBody : messageBodies) {
MessageBuilder msgBuilder = MessageBuilder.create();
msgBuilder.setContent(msgBody);
messagesToSend.add(msgBuilder.build());
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return messagesToSend;
}
Aggregations