Use inline senders on the tenanted Azure Service Bus path (GH-3826) - #3833
Merged
Conversation
TenantedSender deliberately does not implement ISenderRequiresCallback so that SendingAgent picks sendWithExplicitHandlingAsync for the fire-and-forget senders underneath it (GH-2361). But EndpointCollection.CreateSendingAgent only calls RegisterCallback when the *top-level* sender implements that interface, and it does not recurse. A BatchedSender underneath a TenantedSender therefore keeps _callback == null and throws InvalidOperationException: This sender has not been registered. on every batch, so a tenanted Azure Service Bus endpoint could not send anything at all -- including on the untenanted default pathway, which is what GH-3826 reported as "sent and never received". Redis, MQTT and Pub/Sub already hit this and each worked around it by forcing the inline sender on the tenanted path, with a comment naming GH-2361. Azure Service Bus was never given the same treatment. Do that here rather than rework the callback plumbing: BuildInlineSenderForQueue / BuildInlineSenderForTopic already build exactly the right shape, and InlineAzureServiceBusSender awaits the real broker send, so the outbox marks success only after the broker has it. Also fixes the test's tenant management connection string, which pointed at the AMQP endpoint (5673) rather than the management endpoint (5300) and made every tenant provisioning call hang to its own timeout -- the source of the 4m28s the issue described. The class drops from 5m33s to 2m29s. DefaultSender and TenantSenders() are exposed on TenantedSender so the new regression test can assert the shape without reflection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WHAuhdWS3XeAk16swV9G8m
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3826.
Not a routing bug
The issue reported a message published without a tenant id being
Sentand neverReceived, and concluded it was "real multi-tenant conventional-routing behaviour". The route was correct and the listener wasAcceptingthe whole time — the send failed.TenantedSenderdeliberately does not implementISenderRequiresCallback, so thatSendingAgentpickssendWithExplicitHandlingAsyncfor the fire-and-forget senders beneath it (GH-2361). ButEndpointCollection.CreateSendingAgentonly callsRegisterCallbackwhen the top-level sender implements that interface, and it does not recurse:Azure Service Bus put a
BatchedSenderunder theTenantedSender, so_callbackstayed null and every batch threw:So a tenanted ASB endpoint could not send anything — tenanted or untenanted.
The fix follows existing precedent
Redis, MQTT and Pub/Sub each already hit this and worked around it the same way, every one with a comment naming GH-2361 — e.g.
RedisStreamEndpoint:ASB was simply never given the same treatment. This does that, rather than rework the callback plumbing across four transports.
InlineAzureServiceBusSenderawaits the real broker send, so the outbox marks success only after the broker has the message.Also: a test bug worth 2 minutes
The test set the tenant's
ManagementConnectionStringto the AMQP endpoint (5673) instead of the management endpoint (5300), so every tenant provisioning call hung to its own timeout. That is where the issue's 4m28s came from. Class drops 5m33s → 2m29s.Verification
Bug_19332/2, untagged fromCategory=Flaky.tenanted_senders_are_inline_3826asserts the sender shape and that an untenanted publish round-trips.🤖 Generated with Claude Code
https://claude.ai/code/session_01WHAuhdWS3XeAk16swV9G8m