Search in sources :

Example 1 with DispatchHandler

use of com.microsoft.azure.servicebus.amqp.DispatchHandler in project azure-service-bus-java by Azure.

the class CoreMessageReceiver method onReceiveComplete.

@Override
public void onReceiveComplete(Delivery delivery) {
    this.underlyingFactory.getRetryPolicy().resetRetryCount(this.getClientId());
    byte[] deliveryTag = delivery.getTag();
    String deliveryTagAsString = StringUtil.convertBytesToString(delivery.getTag());
    TRACE_LOGGER.debug("Received a delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
    if (deliveryTag == null || deliveryTag.length == 0 || !this.tagsToDeliveriesMap.containsKey(deliveryTagAsString)) {
        TRACE_LOGGER.debug("Received a message from '{}'. Adding to prefecthed messages.", this.receivePath);
        try {
            Message message = Util.readMessageFromDelivery(receiveLink, delivery);
            if (this.settleModePair.getSenderSettleMode() == SenderSettleMode.SETTLED) {
                // No op. Delivery comes settled from the sender
                delivery.disposition(Accepted.getInstance());
                delivery.settle();
            } else {
                this.tagsToDeliveriesMap.put(StringUtil.convertBytesToString(delivery.getTag()), delivery);
                receiveLink.advance();
            }
            // Accuracy of count is not that important. So not making those two operations atomic
            this.currentPrefetechedMessagesCount.incrementAndGet();
            this.prefetchedMessages.add(new MessageWithDeliveryTag(message, delivery.getTag()));
        } catch (Exception e) {
            TRACE_LOGGER.warn("Reading message from delivery '{}' from '{}', session '{}' failed with unexpected exception.", deliveryTagAsString, this.receivePath, this.sessionId, e);
            delivery.disposition(Released.getInstance());
            delivery.settle();
            return;
        }
    } else {
        DeliveryState remoteState = delivery.getRemoteState();
        TRACE_LOGGER.debug("Received a delivery '{}' with state '{}' from '{}'", deliveryTagAsString, remoteState, this.receivePath);
        if (remoteState instanceof Outcome) {
            Outcome remoteOutcome = (Outcome) remoteState;
            UpdateStateWorkItem matchingUpdateStateWorkItem = this.pendingUpdateStateRequests.get(deliveryTagAsString);
            if (matchingUpdateStateWorkItem != null) {
                // This comparison is ugly. Using it for the lack of equals operation on Outcome classes
                if (remoteOutcome.getClass().getName().equals(matchingUpdateStateWorkItem.outcome.getClass().getName())) {
                    TRACE_LOGGER.debug("Completing a pending updateState operation for delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
                    this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, null);
                } else {
                    // if(matchingUpdateStateWorkItem.expectedOutcome instanceof Accepted)
                    // {
                    TRACE_LOGGER.warn("Received delivery '{}' state '{}' doesn't match expected state '{}'", deliveryTagAsString, remoteState, matchingUpdateStateWorkItem.outcome);
                    // Complete requests
                    if (remoteOutcome instanceof Rejected) {
                        Rejected rejected = (Rejected) remoteOutcome;
                        ErrorCondition error = rejected.getError();
                        Exception exception = ExceptionUtil.toException(error);
                        if (ExceptionUtil.isGeneralError(error.getCondition())) {
                            this.lastKnownLinkError = exception;
                            this.lastKnownErrorReportedAt = Instant.now();
                        }
                        Duration retryInterval = this.retryPolicy.getNextRetryInterval(this.getClientId(), exception, matchingUpdateStateWorkItem.getTimeoutTracker().remaining());
                        if (retryInterval == null) {
                            TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                            this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                        } else {
                            matchingUpdateStateWorkItem.setLastKnownException(exception);
                            // Retry after retry interval
                            TRACE_LOGGER.debug("Pending updateState operation for delivery '{}' will be retried after '{}'", deliveryTagAsString, retryInterval);
                            try {
                                this.underlyingFactory.scheduleOnReactorThread((int) retryInterval.toMillis(), new DispatchHandler() {

                                    @Override
                                    public void onEvent() {
                                        delivery.disposition((DeliveryState) matchingUpdateStateWorkItem.getOutcome());
                                    }
                                });
                            } catch (IOException ioException) {
                                this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, new ServiceBusException(false, "Operation failed while scheduling a retry on Reactor, see cause for more details.", ioException));
                            }
                        }
                    } else if (remoteOutcome instanceof Released) {
                        Exception exception = new OperationCancelledException(remoteOutcome.toString());
                        TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                        this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                    } else {
                        Exception exception = new ServiceBusException(false, remoteOutcome.toString());
                        TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                        this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                    }
                // }
                }
            } else {
            // Should not happen. Ignore it
            }
        } else {
        // Ignore it. we are only interested in terminal delivery states
        }
    }
}
Also used : Released(org.apache.qpid.proton.amqp.messaging.Released) Message(org.apache.qpid.proton.message.Message) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) Duration(java.time.Duration) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) IOException(java.io.IOException) IOException(java.io.IOException) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Outcome(org.apache.qpid.proton.amqp.messaging.Outcome)

Example 2 with DispatchHandler

use of com.microsoft.azure.servicebus.amqp.DispatchHandler in project azure-service-bus-java by Azure.

the class CoreMessageReceiver method closeInternals.

private void closeInternals(boolean waitForCloseCompletion) {
    if (!this.getIsClosed()) {
        if (this.receiveLink != null && this.receiveLink.getLocalState() != EndpointState.CLOSED) {
            try {
                this.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() {

                    @Override
                    public void onEvent() {
                        if (CoreMessageReceiver.this.receiveLink != null && CoreMessageReceiver.this.receiveLink.getLocalState() != EndpointState.CLOSED) {
                            TRACE_LOGGER.info("Closing receive link to '{}'", CoreMessageReceiver.this.receivePath);
                            CoreMessageReceiver.this.receiveLink.close();
                            CoreMessageReceiver.this.underlyingFactory.deregisterForConnectionError(CoreMessageReceiver.this.receiveLink);
                            if (waitForCloseCompletion) {
                                CoreMessageReceiver.this.scheduleLinkCloseTimeout(TimeoutTracker.create(CoreMessageReceiver.this.operationTimeout));
                            } else {
                                AsyncUtil.completeFuture(CoreMessageReceiver.this.linkClose, null);
                            }
                        }
                    }
                });
            } catch (IOException e) {
                AsyncUtil.completeFutureExceptionally(this.linkClose, e);
            }
        } else {
            AsyncUtil.completeFuture(this.linkClose, null);
        }
        this.cancelSASTokenRenewTimer();
        this.closeRequestResponseLink();
        this.updateStateRequestsTimeoutChecker.cancel(false);
        this.returnMessagesLoopRunner.cancel(false);
    }
}
Also used : DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) IOException(java.io.IOException)

Example 3 with DispatchHandler

use of com.microsoft.azure.servicebus.amqp.DispatchHandler in project azure-service-bus-java by Azure.

the class CoreMessageReceiver method createLink.

private CompletableFuture<CoreMessageReceiver> createLink() {
    this.linkOpen = new WorkItem<CoreMessageReceiver>(new CompletableFuture<CoreMessageReceiver>(), this.operationTimeout);
    this.scheduleLinkOpenTimeout(this.linkOpen.getTimeoutTracker());
    this.sendTokenAndSetRenewTimer(false).handleAsync((v, sasTokenEx) -> {
        if (sasTokenEx != null) {
            Throwable cause = ExceptionUtil.extractAsyncCompletionCause(sasTokenEx);
            TRACE_LOGGER.error("Sending SAS Token failed. ReceivePath:{}", this.receivePath, cause);
            AsyncUtil.completeFutureExceptionally(this.linkOpen.getWork(), cause);
        } else {
            try {
                this.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() {

                    @Override
                    public void onEvent() {
                        CoreMessageReceiver.this.createReceiveLink();
                    }
                });
            } catch (IOException ioException) {
                this.cancelSASTokenRenewTimer();
                AsyncUtil.completeFutureExceptionally(this.linkOpen.getWork(), new ServiceBusException(false, "Failed to create Receiver, see cause for more details.", ioException));
            }
        }
        return null;
    });
    return this.linkOpen.getWork();
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) IOException(java.io.IOException)

Example 4 with DispatchHandler

use of com.microsoft.azure.servicebus.amqp.DispatchHandler in project azure-service-bus-java by Azure.

the class CoreMessageSender method closeInternals.

private void closeInternals(boolean waitForCloseCompletion) {
    if (!this.getIsClosed()) {
        if (this.sendLink != null && this.sendLink.getLocalState() != EndpointState.CLOSED) {
            try {
                this.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() {

                    @Override
                    public void onEvent() {
                        if (CoreMessageSender.this.sendLink != null && CoreMessageSender.this.sendLink.getLocalState() != EndpointState.CLOSED) {
                            TRACE_LOGGER.info("Closing send link to '{}'", CoreMessageSender.this.sendPath);
                            CoreMessageSender.this.underlyingFactory.deregisterForConnectionError(CoreMessageSender.this.sendLink);
                            CoreMessageSender.this.sendLink.close();
                            if (waitForCloseCompletion) {
                                CoreMessageSender.this.scheduleLinkCloseTimeout(TimeoutTracker.create(CoreMessageSender.this.operationTimeout));
                            } else {
                                AsyncUtil.completeFuture(CoreMessageSender.this.linkClose, null);
                            }
                        }
                    }
                });
            } catch (IOException e) {
                AsyncUtil.completeFutureExceptionally(this.linkClose, e);
            }
        } else {
            AsyncUtil.completeFuture(this.linkClose, null);
        }
        this.cancelSASTokenRenewTimer();
        this.closeRequestResponseLink();
    }
}
Also used : DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) IOException(java.io.IOException)

Example 5 with DispatchHandler

use of com.microsoft.azure.servicebus.amqp.DispatchHandler in project azure-service-bus-java by Azure.

the class CoreMessageSender method create.

public static CompletableFuture<CoreMessageSender> create(final MessagingFactory factory, final String sendLinkName, final String senderPath) {
    TRACE_LOGGER.info("Creating core message sender to '{}'", senderPath);
    final CoreMessageSender msgSender = new CoreMessageSender(factory, sendLinkName, senderPath);
    TimeoutTracker openLinkTracker = TimeoutTracker.create(factory.getOperationTimeout());
    msgSender.initializeLinkOpen(openLinkTracker);
    msgSender.sendTokenAndSetRenewTimer(false).handleAsync((v, sasTokenEx) -> {
        if (sasTokenEx != null) {
            Throwable cause = ExceptionUtil.extractAsyncCompletionCause(sasTokenEx);
            TRACE_LOGGER.error("Sending SAS Token to '{}' failed.", msgSender.sendPath, cause);
            msgSender.linkFirstOpen.completeExceptionally(cause);
        } else {
            try {
                msgSender.underlyingFactory.scheduleOnReactorThread(new DispatchHandler() {

                    @Override
                    public void onEvent() {
                        msgSender.createSendLink();
                    }
                });
            } catch (IOException ioException) {
                msgSender.cancelSASTokenRenewTimer();
                msgSender.linkFirstOpen.completeExceptionally(new ServiceBusException(false, "Failed to create Sender, see cause for more details.", ioException));
            }
        }
        return null;
    });
    return msgSender.linkFirstOpen;
}
Also used : DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) IOException(java.io.IOException)

Aggregations

DispatchHandler (com.microsoft.azure.servicebus.amqp.DispatchHandler)13 IOException (java.io.IOException)13 CompletableFuture (java.util.concurrent.CompletableFuture)3 Duration (java.time.Duration)2 DeliveryState (org.apache.qpid.proton.amqp.transport.DeliveryState)2 UnresolvedAddressException (java.nio.channels.UnresolvedAddressException)1 ExecutionException (java.util.concurrent.ExecutionException)1 Outcome (org.apache.qpid.proton.amqp.messaging.Outcome)1 Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)1 Released (org.apache.qpid.proton.amqp.messaging.Released)1 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)1 Delivery (org.apache.qpid.proton.engine.Delivery)1 HandlerException (org.apache.qpid.proton.engine.HandlerException)1 Message (org.apache.qpid.proton.message.Message)1