@Override protected CompletableFuture<Void> onClose() { TRACE_LOGGER.info("Closing message and session pump on entity '{}'", this.entityPath); CompletableFuture[] closeFutures = new CompletableFuture[this.openSessions.size() + 1]; int arrayIndex = 0; for (IMessageSession session : this.openSessions.values()) { closeFutures[arrayIndex++] = session.closeAsync(); } closeFutures[arrayIndex] = this.innerReceiver == null ? CompletableFuture.completedFuture(null) : this.innerReceiver.closeAsync(); return CompletableFuture.allOf(closeFutures); }
SessionRenewLockLoop(IMessageSession session, MessageAndSessionPump messageAndSessionPump) { super(); this.session = session; this.messageAndSessionPump = messageAndSessionPump; this.sessionIdentifier = String.format("session with id:%s", this.session.getSessionId()); }
private void receiveFromSessionAndPumpMessage(SessionTracker sessionTracker) { if (!this.getIsClosingOrClosed()) { IMessageSession session = sessionTracker.getSession(); CompletableFuture<IMessage> receiverFuture = session.receiveAsync(this.sessionHandlerOptions.getMessageWaitDuration()); receiverFuture.handleAsync((message, receiveEx) -> { if (receiveEx != null) { receiveEx = ExceptionUtil.extractAsyncCompletionCause(receiveEx); TRACE_LOGGER.error("Receiving message from session '{}' on entity '{}' failed.", session.getSessionId(), this.entityPath, receiveEx); this.notifyExceptionToSessionHandler(receiveEx, ExceptionPhase.RECEIVE); sessionTracker.shouldRetryOnNoMessageOrException().thenAcceptAsync((shouldRetry) -> { } else { if (message == null) { TRACE_LOGGER.debug("Receive from from session '{}' on entity '{}' returned no messages.", session.getSessionId(), this.entityPath); sessionTracker.shouldRetryOnNoMessageOrException().thenAcceptAsync((shouldRetry) -> { if (shouldRetry) { TRACE_LOGGER.trace("Message with sequence number '{}' received from session '{}' on entity '{}'.", message.getSequenceNumber(), session.getSessionId(), this.entityPath); sessionTracker.notifyMessageReceived(); TRACE_LOGGER.warn("onMessage task timed out. Cancelling loop to renew lock on session '{}'", session.getSessionId()); sessionTracker.sessionRenewLockLoop.cancelLoop(); }, if (this.sessionHandlerOptions.isAutoComplete()) { TRACE_LOGGER.debug("Completing message with sequence number '{}'", message.getSequenceNumber()); updateDispositionFuture = session.completeAsync(message.getLockToken()); } else { updateDispositionFuture = CompletableFuture.completedFuture(null);
TRACE_LOGGER.info("No messages recevied by any receive call from session '{}'. Closing the session.", this.session.getSessionId()); this.retryFuture.complete(false); TRACE_LOGGER.warn("Closing session timed out. Cancelling loop to renew lock on session '{}'", this.session.getSessionId()); SessionTracker.this.sessionRenewLockLoop.cancelLoop(); }, onCloseFuture = COMPLETED_FUTURE.thenComposeAsync((v) -> this.messageAndSessionPump.sessionHandler.OnCloseSessionAsync(session), this.messageAndSessionPump.customCodeExecutor); } catch (Exception onCloseSyncEx) { TRACE_LOGGER.error("Invocation of onCloseSession on session '{}' threw unexpected exception", this.session.getSessionId(), onCloseSyncEx); onCloseFuture = new CompletableFuture<Void>(); onCloseFuture.completeExceptionally(onCloseSyncEx); if (onCloseEx != null) { onCloseEx = ExceptionUtil.extractAsyncCompletionCause(onCloseEx); TRACE_LOGGER.error("onCloseSession on session '{}' threw exception", session.getSessionId(), onCloseEx); this.messageAndSessionPump.notifyExceptionToSessionHandler(onCloseEx, ExceptionPhase.USERCALLBACK); TRACE_LOGGER.debug("Cancelled loop to renew lock on session '{}'", this.session.getSessionId()); this.session.closeAsync().handleAsync((z, closeEx) -> TRACE_LOGGER.info("Closing session '{}' from entity '{}' failed", this.session.getSessionId(), this.messageAndSessionPump.entityPath, closeEx); this.messageAndSessionPump.notifyExceptionToSessionHandler(closeEx, ExceptionPhase.SESSIONCLOSE); } else { TRACE_LOGGER.info("Closed session '{}' from entity '{}'", this.session.getSessionId(), this.messageAndSessionPump.entityPath); this.messageAndSessionPump.openSessions.remove(this.session.getSessionId()); this.messageAndSessionPump.acceptSessionAndPumpMessages(); return null;
TRACE_LOGGER.debug("Accepted a session '{}' from entity '{}'", session.getSessionId(), this.entityPath); if(this.prefetchCount != UNSET_PREFETCH_COUNT) session.setPrefetchCount(this.prefetchCount); } catch (ServiceBusException e) { this.openSessions.put(session.getSessionId(), session); SessionRenewLockLoop sessionRenewLockLoop = new SessionRenewLockLoop(session, this); sessionRenewLockLoop.startLoop(); TRACE_LOGGER.debug("Started loop to renew lock on session '{}'", session.getSessionId()); SessionTracker sessionTracker = new SessionTracker(this, session, sessionRenewLockLoop); for (int i = 0; i < this.sessionHandlerOptions.getMaxConcurrentCallsPerSession(); i++) {
@Override protected void loop() { if (!this.isCancelled()) { Duration renewInterval = RenewLockLoop.getNextRenewInterval(this.session.getLockedUntilUtc(), this.sessionIdentifier); if (renewInterval != null && !renewInterval.isNegative()) { this.timerFuture = Timer.schedule(() -> { TRACE_LOGGER.debug("Renewing lock on '{}'", this.sessionIdentifier); this.session.renewSessionLockAsync().handleAsync((v, renewLockEx) -> { if (renewLockEx != null) { renewLockEx = ExceptionUtil.extractAsyncCompletionCause(renewLockEx); TRACE_LOGGER.error("Renewing lock on '{}' failed", this.sessionIdentifier, renewLockEx); this.messageAndSessionPump.notifyExceptionToSessionHandler(renewLockEx, ExceptionPhase.RENEWSESSIONLOCK); if (!(renewLockEx instanceof SessionLockLostException || renewLockEx instanceof OperationCancelledException)) { this.loop(); } } else { TRACE_LOGGER.debug("Renewed lock on '{}'", this.sessionIdentifier); this.loop(); } return null; }, MessagingFactory.INTERNAL_THREAD_POOL); }, renewInterval, TimerType.OneTimeRun); } } } }
@Override public void setPrefetchCount(int prefetchCount) throws ServiceBusException { if(prefetchCount < 0) { throw new IllegalArgumentException("Prefetch count cannot be negative."); } this.prefetchCount = prefetchCount; if(this.innerReceiver != null) { this.innerReceiver.setPrefetchCount(prefetchCount); } // For accepted session receivers also IMessageSession[] currentAcceptedSessions = this.openSessions.values().toArray(new IMessageSession[0]); for(IMessageSession session : currentAcceptedSessions) { try { session.setPrefetchCount(prefetchCount); } catch(IllegalStateException ise) { // Session might have been closed.. Ignore the exception as this is a best effort setter on already accepted sessions } } } }
synchronized void notifyMessageReceived() { TRACE_LOGGER.trace("Message received from session '{}'", this.session.getSessionId()); if (this.retryFuture != null && !this.retryFuture.isDone()) { this.waitingRetryThreads = 0; this.retryFuture.complete(true); } }