Skip to content

FromHandlerType routing: create listeners for separated handler chains, not just the saga (#3041) - #3042

Merged
jeremydmiller merged 1 commit into
mainfrom
fix-3041-fromhandlertype-saga-separated-handler
Jun 5, 2026
Merged

jeremydmiller merged 1 commit into
mainfrom
fix-3041-fromhandlertype-saga-separated-handler

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3041.

Reproduction

From the reporter's repo: RabbitMQ + UseConventionalRouting(NamingSource.FromHandlerType) + DisableConventionalLocalRouting() + MultipleHandlerBehavior.Separated, with a message handled by both a saga (a Start method) and a regular handler. Only the saga ran; the regular handler never received the message.

I reproduced it broker-free by inspecting the SagaChain for the shared message type:

chain type      : SagaChain
chain.Handlers  : [ReproSaga.Start]          // the saga only
chain.ByEndpoint: [ReproRegularHandler]      // the regular handler is a SEPARATED chain

(The reporter's own diagnostic — runtime.RoutingFor(messageType).Routes — points at the sender/exchange side; the actual missing piece is on the listener side, which the endpoint/queue diagnostics surface: only the saga's queue gets created.)

Root cause

Under MultipleHandlerBehavior.Separated, when a message has multiple handlers and one is a saga, only the saga stays in chain.Handlers — the sibling handlers are moved to separated chains in chain.ByEndpoint. MessageRoutingConvention.DiscoverListeners' FromHandlerType branch iterated only chain.Handlers, so it created a handler-named listener queue for the saga but none for the separated regular handler. With conventional local routing disabled, that handler had no queue/listener and never received the message. (The Separated branch handles ByEndpoint, but FromHandlerType takes the earlier if and never reaches it.)

Fix

The FromHandlerType branch now also creates a handler-named listener for each chain.ByEndpoint chain — registering the endpoint on that chain and marking it sticky, mirroring what the Separated branch already does — and is entered when there are only ByEndpoint chains too. One small change in MessageRoutingConvention.

Tests

New RabbitMQ regression Bug_3041_saga_and_handler_with_handler_type_naming (mirrors the repro): asserts both the saga's and the regular handler's handler-named queues exist and have active listeners. Verified it fails (regular-handler queue missing) without the fix.

  • RabbitMQ conventional-routing + separated suites: 34.
  • MessageRoutingTests: 25. CoreTests saga/separated: 66.

No version bump — main is unpublished 6.4.4 (latest tag V6.4.1); rides the pending release.

🤖 Generated with Claude Code

…handler chains too (GH-3041)

When a message is handled by more than one handler under MultipleHandlerBehavior.Separated and one of
them is a saga (e.g. a Start method), only the saga stays in chain.Handlers - the sibling handlers are
moved to separated chains in chain.ByEndpoint. MessageRoutingConvention.DiscoverListeners' FromHandlerType
branch iterated only chain.Handlers, so it created a handler-named listener for the saga but none for the
separated regular handler. With conventional local routing disabled, the regular handler's message never
arrived (no queue/listener for it) - only the saga ran.

Fix: the FromHandlerType branch now also creates a handler-named listener for each chain.ByEndpoint chain,
registers the endpoint on that chain, and marks it sticky - mirroring what the Separated branch already
does. The branch is also entered when there are only ByEndpoint chains.

Reproduced from the issue's repo (RabbitMQ + UseConventionalRouting(FromHandlerType) +
DisableConventionalLocalRouting + Separated, a saga Start and a regular Handle for one message). Root
cause pinned by inspecting the SagaChain: chain.Handlers = [saga], chain.ByEndpoint = [regular handler].
New RabbitMQ regression test asserts both handler-named queues exist and have active listeners; verified
it fails (regular-handler queue missing) without the fix. RabbitMQ conventional-routing (34),
MessageRoutingTests (25), and CoreTests saga/separated (66) all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit b2e0953 into main Jun 5, 2026
24 checks passed
This was referenced Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

With NamingSource.FromHandlerType, only Saga handler receives messages when a Saga and a regular handler are both registered for the same message type

1 participant