Skip to content

Run RabbitMQ deliveries through the core DeliveryDispatcher, with one scope per consumer attempt and no reply on shutdown - #423

Merged
Vulthil merged 2 commits into
mainfrom
refactor/rabbitmq-delivery-dispatch
Sep 30, 2026
Merged

Vulthil merged 2 commits into
mainfrom
refactor/rabbitmq-delivery-dispatch

Conversation

@Vulthil

@Vulthil Vulthil commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Summary

Moves the RabbitMQ transport onto the core DeliveryDispatcher from #422. The worker keeps only the AMQP parts: ack,
nack for dead-lettering, the retry-queue re-publish, the fault route and the reply route.

Production behavior changes

  • Every consumer attempt runs in its own DI scope. Before, all consumers of one delivery shared one scope per round,
    so a failed consumer's scoped state (for example an unsaved DbContext) could reach the next consumer.
  • A request consumer stopped by shutdown sends no reply, and the delivery stays unsettled so the broker delivers it
    again. Before, it replied with an RpcFault ("A task was canceled").
  • A fault's OriginalContext is the context of the attempt that failed for good, so its RetryCount is the round the
    consumer failed on. For a one-way envelope delivery its RequestId is now empty; it held the AMQP correlation id.
    The fault's Message is still the payload as delivered.
  • Logging: the RabbitMQ events 1103–1105 are removed, and the dispatcher's 2200–2202 replace them. Each delivery opens
    a logging scope with the queue, the routing key and the message type, so those entries keep that context.
  • Tracing: every failed attempt is recorded as an exception event on the delivery's receive span.

Fix

  • WithRetryCount and the retry re-publish copied the delivery's AMQP properties, but the copy shared the header
    dictionary with the delivery, so setting x-retry-count also changed the original delivery. Both now copy the
    headers.

Code

  • MessageHandler, RabbitMqHandlerFactory and GatedPublisher are deleted. QueueDispatchPlans builds
    DeliveryHandlers with DeliveryHandlerFactory.
  • RabbitMqBus takes the DeliveryDispatcher from DI instead of an IServiceScopeFactory.
  • No public API change: every changed type is internal.

Tests

  • ConsumeFilterPipelineTests, PolymorphicDispatchTests and RecordingGatedPublisher are deleted, because they
    tested pipeline and dispatch rules the core now owns. A core test pins that a request's filters finish before its
    reply is sent, and a plan test pins which consumers a polymorphic plan holds.
  • The worker retry tests keep the AMQP specifics: retry queue, TTL, headers, ack/nack, in-process wait and shutdown.
  • New worker tests: the reply route and correlation id, no reply on shutdown, the logging scope reaching the
    dispatcher's entries, the fault round, and WithRetryCount leaving the delivery unchanged.

Docs

  • Retries: the scope rule and the shutdown rule. Faults: OriginalContext is the failing attempt. Request/Reply: no
    reply on shutdown. Observability: the dispatcher's log events, the delivery scope and the span events.

Verification

  • Full solution build: 0 warnings, 0 errors.
  • All test projects pass on net10.0 and net9.0. This includes Vulthil.IntegrationTests (Testcontainers with a real
    broker, 68 tests) and the Aspire messaging integration tests (net10.0, 13 tests).
  • Mutation checks:
    • Publishing the fault with the old delivery snapshot fails the fault-round test.
    • Opening the delivery scope on another logger fails the log-scope test.
  • dotnet pack of Vulthil.Messaging.RabbitMq passes package validation against the 1.2.0 baseline.

Backport to v1.0: no

@claude

claude Bot commented Sep 30, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

@Vulthil
Vulthil merged commit 0371f3e into main Sep 30, 2026
7 checks passed
@Vulthil
Vulthil deleted the refactor/rabbitmq-delivery-dispatch branch September 30, 2026 20:08
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.

1 participant