[Service Bus] Fix spurious DeliveryNotOnLinkException in session processor (#47356)#49603
Conversation
…essor (Azure#47356) A session-enabled ServiceBusProcessorClient that settles messages manually (e.g. complete()) while auto-complete is left enabled logged a spurious DeliveryNotOnLinkException ("...does not exist in the link's DeliveryMap") at ERROR. The V2 session disposition path (SessionsMessagePump) never called message.setIsSettled() on success, so the isSettled() guard could not absorb the redundant auto-settlement the way the non-session and V1 session paths do. The second disposition then reached the receive-link after the delivery had already been removed from the DeliveryMap, producing the error log. The message was always settled correctly on the broker; only the misleading ERROR log is removed. Now the session path marks the message settled on a successful disposition, mirroring ServiceBusReceiverAsyncClient, so a redundant settle short-circuits at the already-settled guard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thank you for your contribution @ksalazar-91! We will review the pull request and get back to you soon. |
There was a problem hiding this comment.
Pull request overview
This PR fixes a misleading DeliveryNotOnLinkException ERROR log that can occur in session-enabled ServiceBusProcessorClient when a message is settled manually inside the handler while auto-complete is still enabled, by ensuring the V2 session disposition path marks messages as settled after a successful disposition.
Changes:
- Mark
ServiceBusReceivedMessageas settled (message.setIsSettled()) after a successful disposition in the V2 session path to activate the existingmessage.isSettled()guard on redundant settlements. - Add a release note describing the removed spurious error log and clarifying that broker settlement was already succeeding.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| sdk/servicebus/azure-messaging-servicebus/src/main/java/com/azure/messaging/servicebus/SessionsMessagePump.java | Marks messages as settled on successful session disposition to prevent redundant settle attempts from reaching the receive-link. |
| sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md | Documents the bug fix in 7.18.0-beta.2 (Unreleased) under “Bugs Fixed”. |
| updateDispositionMono = receiver.updateDisposition(message.getLockToken(), deliveryState) | ||
| .doOnSuccess(__ -> message.setIsSettled()); |
There was a problem hiding this comment.
Added a regression test in the latest push (commit 5e9b2ff): SessionsMessagePumpIsolatedTest#shouldNotReDispositionWhenHandlerSettlesWithAutoCompleteEnabled. It runs a session message through the pump with auto-complete enabled and a handler that calls complete() manually, then asserts (1) message.isSettled() becomes true (setIsSettled() invoked once), and (2) the receive-link sees exactly one updateDisposition call — proving the redundant auto-settlement short-circuits at the isSettled() guard and never issues a second disposition that would raise DeliveryNotOnLinkException. Verified passing (3/3 with related disposition tests); checkstyle + spotbugs clean.
) Adds SessionsMessagePumpIsolatedTest#shouldNotReDispositionWhenHandlerSettlesWithAutoCompleteEnabled, covering the V2 session path where a handler settles a message manually while auto-complete is enabled. Verifies the message is marked settled and the redundant auto-settlement short-circuits at the isSettled() guard so the receive-link sees exactly one disposition (no second attempt that would raise DeliveryNotOnLinkException). Addresses the PR review feedback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Fixes #47356.
A session-enabled
ServiceBusProcessorClient(PEEK_LOCK) that settles messages manually inside the handler — e.g. callingcontext.complete()— while auto-complete is left enabled (the default) intermittently logged a spurious error atERROR:The message is already settled correctly on the broker; the only symptom is this misleading
DeliveryNotOnLinkExceptionlog line (one per message). No messages are lost or redelivered, andprocessErroris not invoked.Root cause
The processor's auto-disposition feature settles a message after the handler returns. When the handler also settles manually, two dispositions are issued for the same delivery. The SDK is designed to absorb this redundant settle via the
message.isSettled()guard inupdateDisposition:The non-session and V1-session paths arm this guard by calling
message.setIsSettled()on a successful disposition (ServiceBusReceiverAsyncClient). The V2 session path (SessionsMessagePump.SessionReceiversTracker.updateDisposition) never did. So the flag stayedfalse, the guard could not trip, and the redundant auto-complete proceeded to a second link-level disposition on a delivery that had already been removed from theDeliveryMap— producing theDeliveryNotOnLinkExceptionERROR.Fix
Mark the message settled on a successful disposition in the V2 session path, mirroring the sibling paths:
This arms the existing
isSettled()guard so a redundant settle short-circuits with the benign "already settled" error (swallowed at verbose by the auto-disposition wrapper) instead of reaching the receive-link. The change is package-local toazure-messaging-servicebus; noazure-core-amqpchange is needed.Verification
Reproduced live against a Standard namespace with a session-enabled subscription, sending 5 messages to one session and a session processor that calls
complete()manually with auto-complete enabled.disableAutoComplete()The fix removes the error log with auto-complete still enabled (no customer config change required) and does not regress the manual-settlement path.
Notes for reviewers
disableAutoComplete()remains the recommended pattern when settling manually; this PR additionally makes the SDK fail quietly and consistently on a redundant settle for session processors, matching the documented "auto-settle is tolerated" behavior already present in the other receive paths.7.18.0-beta.2 (Unreleased)→ Bugs Fixed.