Include transport scheme in listener agent URIs to avoid cross-transport collision (GH-3027)#3028
Merged
Merged
Conversation
…ort collision (GH-3027) A single host listening on the same logical queue name across multiple transports — e.g. a "critterwatch" queue on both Rabbit and SQS, each with ListenOnlyAtLeader() (or the sharded / exclusive path under cluster partitioning) — crashed on startup with "An item with the same key has already been added. Key: wolverine-leader-listener://critterwatch/". The leader-pinned and exclusive listener agent URIs were composed from only the family scheme + Endpoint.EndpointName, with no transport identifier, so two endpoints sharing an EndpointName across different transports produced identical agent URIs and collided in the family ctor's .ToDictionary(e => e.Uri). Both LeaderPinnedListenerAgent and ExclusiveListenerAgent now fold the endpoint's transport scheme into the agent URI (wolverine-leader-listener://rabbitmq/critterwatch, .../sqs/critterwatch, ...). The composition is self-consistent — the family keys its dictionary and resolves BuildAgentAsync/EvaluateAssignmentsAsync off the same agent.Uri — and single-transport hosts behave identically (the URI just gains a transport segment). No external code parses these agent URIs by string convention (the only "wolverine-listener" literal elsewhere is the unrelated health-check name). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 8, 2026
Merged
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 #3027.
Problem
A single host listening on the same logical queue name across multiple transports — e.g. a
"critterwatch"queue on Rabbit + SQS + Azure Service Bus, each withListenOnlyAtLeader()— crashed on startup:The same shape hit the non-leader-pinned
ExclusiveListenerFamilypath under cluster partitioning with multipleUseShardedXxxQueues("critterwatch", n)calls.Root cause
LeaderPinnedListenerAgentandExclusiveListenerAgentcomposed their agent URI from only the family scheme +Endpoint.EndpointName, with no transport identifier:Two endpoints sharing an
EndpointNameacross different transports produced identical agent URIs, and the family ctors collide on.ToDictionary(e => e.Uri).Fix
Fold the endpoint's transport scheme into the agent URI in both agents:
Produces distinct keys —
wolverine-leader-listener://rabbitmq/critterwatch,.../sqs/critterwatch,.../azure-service-bus/critterwatch.The composition is self-consistent: each family keys its dictionary off
agent.Uriand resolvesBuildAgentAsync/EvaluateAssignmentsAsyncoff the same value, so registration and lookup stay aligned. Single-transport hosts behave identically (the URI just gains a transport segment). Grepped forwolverine-leader-listener/wolverine-listenerliteral usages — no external code parses these agent URIs by string convention (the onlywolverine-listenerliteral elsewhere is the unrelated health-check name).Tests
New
listener_agent_uri_includes_transport_scheme(CoreTests) — verifies both agents carry the transport scheme and that three same-named endpoints across transports no longer collide in the.ToDictionary(e => e.Uri)that the family ctors use. All three cases fail without the fix, pass with it.wolverine.slnxRelease build: 0 warnings, 0 errors.Runtime.Agentssuite: 92 passing.🤖 Generated with Claude Code