@Override public Message readNext(int timeout, TimeUnit unit) throws PulsarClientException { Message msg = consumer.receive(timeout, unit); if (msg != null) { consumer.acknowledgeCumulativeAsync(msg); } return msg; }
@Override public void close() throws IOException { consumer.close(); }
@Override public CompletableFuture<Void> closeAsync() { return consumer.closeAsync(); }
@Override public CompletableFuture<Message> readNextAsync() { return consumer.receiveAsync().thenApply(msg -> { consumer.acknowledgeCumulativeAsync(msg); return msg; }); }
private void starReceivingMessages() throws PulsarClientException { for (ConsumerImpl consumer : consumers) { consumer.sendFlowPermitsToBroker(consumer.cnx(), conf.getReceiverQueueSize()); receiveMessageFromConsumer(consumer); } }
@Override void connectionOpened(final ClientCnx cnx) { setClientCnx(cnx); cnx.registerConsumer(consumerId, this); synchronized (this) { currentSize = incomingMessages.size(); startMessageId = clearReceiverQueue(); unAckedMessageTracker.clear(); batchMessageAckTracker.clear(); ByteBuf request = Commands.newSubscribe(topic, subscription, consumerId, requestId, getSubType(), priorityLevel, consumerName, isDurable, startMessageIdData); if (startMessageIdData != null) { if (changeToReadyState()) { log.info("[{}][{}] Subscribed to topic on {} -- consumer: {}", topic, subscription, cnx.channel().remoteAddress(), consumerId); sendFlowPermitsToBroker(cnx, 1); setState(State.Closed); cnx.removeConsumer(consumerId); cnx.channel().close(); resetBackoff(); sendFlowPermitsToBroker(cnx, conf.getReceiverQueueSize()); if (getState() == State.Closing || getState() == State.Closed) {
if (!verifyChecksum(headersAndPayload, messageId)) { discardCorruptedMessage(messageId, cnx, ValidationError.ChecksumMismatch); return; msgMetadata = Commands.parseMessageMetadata(payload); } catch (Throwable t) { discardCorruptedMessage(messageId, cnx, ValidationError.ChecksumMismatch); return; ByteBuf uncompressedPayload = uncompressPayloadIfNeeded(messageId, msgMetadata, payload, cnx); if (uncompressedPayload == null) { getPartitionIndex(), cnx); uncompressedPayload.release(); msgMetadata.recycle(); notifyPendingReceivedCallback(message, null); closeAsync().handle((ok, e) -> { notifyPendingReceivedCallback(null, new PulsarClientException.InvalidMessageException( format("Unsupported Batch message with 0 size receiver queue for [%s]-[%s] ", receiveIndividualMessagesFromBatch(msgMetadata, uncompressedPayload, messageId, cnx); for (int i = 0; i < numMessages; i++) { try {
if (conf.getSubscriptionType() != SubscriptionType.Shared) { redeliverUnacknowledgedMessages(); return; ClientCnx cnx = cnx(); if (isConnected() && cnx.getRemoteEndpointProtocolVersion() >= ProtocolVersion.v2.getNumber()) { int messagesFromQueue = removeExpiredMessagesFromQueue(messageIds); Iterable<List<MessageIdImpl>> batches = Iterables.partition(messageIds, MAX_REDELIVER_UNACKNOWLEDGED); MessageIdData.Builder builder = MessageIdData.newBuilder(); }); if (messagesFromQueue > 0) { increaseAvailablePermits(cnx, messagesFromQueue); if (cnx == null || (getState() == State.Connecting)) { log.warn("[{}] Client Connection needs to be establised for redelivery of unacknowledged messages", this); } else {
@Override public CompletableFuture<Void> unsubscribeAsync() { if (getState() == State.Closing || getState() == State.Closed) { return FutureUtil .failedFuture(new PulsarClientException.AlreadyClosedException("Consumer was already closed")); } final CompletableFuture<Void> unsubscribeFuture = new CompletableFuture<>(); if (isConnected()) { setState(State.Closing); long requestId = client.newRequestId(); ByteBuf unsubscribe = Commands.newUnsubscribe(consumerId, requestId); ClientCnx cnx = cnx(); cnx.sendRequestWithId(unsubscribe, requestId).thenRun(() -> { cnx.removeConsumer(consumerId); log.info("[{}][{}] Successfully unsubscribed from topic", topic, subscription); batchMessageAckTracker.clear(); unAckedMessageTracker.close(); unsubscribeFuture.complete(null); setState(State.Closed); }).exceptionally(e -> { log.error("[{}][{}] Failed to unsubscribe: {}", topic, subscription, e.getCause().getMessage()); unsubscribeFuture.completeExceptionally(e.getCause()); setState(State.Ready); return null; }); } else { unsubscribeFuture.completeExceptionally(new PulsarClientException("Not connected to broker")); } return unsubscribeFuture; }
@Override public void redeliverUnacknowledgedMessages() { ClientCnx cnx = cnx(); if (isConnected() && cnx.getRemoteEndpointProtocolVersion() >= ProtocolVersion.v2.getNumber()) { int currentSize = 0; synchronized (this) { currentSize = incomingMessages.size(); incomingMessages.clear(); unAckedMessageTracker.clear(); batchMessageAckTracker.clear(); } cnx.ctx().writeAndFlush(Commands.newRedeliverUnacknowledgedMessages(consumerId), cnx.ctx().voidPromise()); if (currentSize > 0) { increaseAvailablePermits(cnx, currentSize); } if (log.isDebugEnabled()) { log.debug("[{}] [{}] [{}] Redeliver unacked messages and send {} permits", subscription, topic, consumerName, currentSize); } return; } if (cnx == null || (getState() == State.Connecting)) { log.warn("[{}] Client Connection needs to be establised for redelivery of unacknowledged messages", this); } else { log.warn("[{}] Reconnecting the client to redeliver the messages.", this); cnx.ctx().close(); } }
@Override protected CompletableFuture<Message> internalReceiveAsync() { CompletableFuture<Message> result = new CompletableFuture<Message>(); Message message = null; try { lock.writeLock().lock(); message = incomingMessages.poll(0, TimeUnit.MILLISECONDS); if (message == null) { pendingReceives.add(result); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); result.completeExceptionally(e); } finally { lock.writeLock().unlock(); } if (message == null && conf.getReceiverQueueSize() == 0) { sendFlowPermitsToBroker(cnx(), 1); } else if (message != null) { messageProcessed(message); result.complete(message); } return result; }
if (isConnected()) { sendFlowPermitsToBroker(cnx(), 1); if (msgCnx == cnx()) { waitingOnReceiveForZeroQueueSize = false; break;
if (isConnected()) { cnx().ctx().writeAndFlush(cmd).addListener(new GenericFutureListener<Future<Void>>() { @Override public void operationComplete(Future<Void> future) throws Exception { stats.incrementNumAcksFailed(); ackFuture .completeExceptionally(new PulsarClientException("Not connected to broker. State: " + getState()));
getPartitionIndex()); bitSet.set(0, batchSize); if (log.isDebugEnabled()) { singleMessageMetadataBuilder, i, batchSize); BatchMessageIdImpl batchMessageIdImpl = new BatchMessageIdImpl(messageId.getLedgerId(), messageId.getEntryId(), getPartitionIndex(), i); final MessageImpl message = new MessageImpl(batchMessageIdImpl, msgMetadata, singleMessageMetadataBuilder.build(), singleMessagePayload, cnx); incomingMessages.add(message); } else { notifyPendingReceivedCallback(message, null); discardCorruptedMessage(messageId, cnx, ValidationError.BatchDeSerializeError);
/** * Record the event that one message has been processed by the application. * * Periodically, it sends a Flow command to notify the broker that it can push more messages */ protected synchronized void messageProcessed(Message msg) { ClientCnx currentCnx = cnx(); ClientCnx msgCnx = ((MessageImpl) msg).getCnx(); lastDequeuedMessage = (MessageIdImpl) msg.getMessageId(); if (msgCnx != currentCnx) { // The processed message did belong to the old queue that was cleared after reconnection. return; } increaseAvailablePermits(currentCnx); stats.updateNumMsgsReceived(msg); if (conf.getAckTimeoutMillis() != 0) { // reset timer for messages that are received by the client MessageIdImpl id = (MessageIdImpl) msg.getMessageId(); if (id instanceof BatchMessageIdImpl) { id = new MessageIdImpl(id.getLedgerId(), id.getEntryId(), getPartitionIndex()); } unAckedMessageTracker.add(id); } }
for (int partitionIndex = 0; partitionIndex < numPartitions; partitionIndex++) { String partitionName = DestinationName.get(topic).getPartition(partitionIndex).toString(); ConsumerImpl consumer = new ConsumerImpl(client, partitionName, subscription, internalConfig, client.externalExecutorProvider().getExecutor(), partitionIndex, new CompletableFuture<Consumer>()); consumers.add(consumer); consumer.subscribeFuture().handle((cons, subscribeException) -> { if (subscribeException != null) { setState(State.Failed);
@Override protected void handleCloseConsumer(CommandCloseConsumer closeConsumer) { log.info("[{}] Broker notification of Closed consumer: {}", remoteAddress, closeConsumer.getConsumerId()); final long consumerId = closeConsumer.getConsumerId(); ConsumerImpl consumer = consumers.get(consumerId); if (consumer != null) { consumer.connectionClosed(this); } else { log.warn("Consumer with id {} not found while closing consumer ", consumerId); } }
metadata.partitions, listenerThread, consumerSubscribedFuture); } else { consumer = new ConsumerImpl(PulsarClientImpl.this, topic, subscription, conf, listenerThread, -1, consumerSubscribedFuture);
private ByteBuf uncompressPayloadIfNeeded(MessageIdData messageId, MessageMetadata msgMetadata, ByteBuf payload, ClientCnx currentCnx) { CompressionType compressionType = msgMetadata.getCompression(); CompressionCodec codec = codecProvider.getCodec(compressionType); int uncompressedSize = msgMetadata.getUncompressedSize(); if (uncompressedSize > PulsarDecoder.MaxMessageSize) { // Uncompressed size is itself corrupted since it cannot be bigger than the MaxMessageSize log.error("[{}][{}] Got corrupted uncompressed message size {} at {}", topic, subscription, uncompressedSize, messageId); discardCorruptedMessage(messageId, currentCnx, ValidationError.UncompressedSizeCorruption); return null; } try { ByteBuf uncompressedPayload = codec.decode(payload, uncompressedSize); return uncompressedPayload; } catch (IOException e) { log.error("[{}][{}] Failed to decompress message with {} at {}: {}", topic, subscription, compressionType, messageId, e.getMessage(), e); discardCorruptedMessage(messageId, currentCnx, ValidationError.DecompressionError); return null; } }
ackMessagesInEarlierBatch(batchMessageId, message);