Skip to content

[Mocha] Fix RabbitMQ sends to undeclared queues failing under explicit binding - #10484

Open
alisan3 wants to merge 2 commits into
ChilliCream:mainfrom
alisan3:ali/mocha-rabbitmq-external-dispatch-destinations
Open

alisan3 wants to merge 2 commits into
ChilliCream:mainfrom
alisan3:ali/mocha-rabbitmq-external-dispatch-destinations

Conversation

@alisan3

@alisan3 alisan3 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Under BindExplicitly(), a send addressed by URI, bus.SendAsync(message, new SendOptions { Endpoint = new Uri("rabbitmq:q/<name>") }), failed with InvalidOperationException("Queue not found") unless <name> was declared in the sending host's own topology. The routing strategy created a dispatch endpoint configuration from the address, but RabbitMQDispatchEndpoint.OnComplete required the queue to be a topology resource, and in explicit mode the address-created endpoint does not add one. The only workaround was to declare every foreign queue locally with DeclareQueue(name).AutoProvision(false).

A point-to-point send to a queue another service owns has no topology-ownership implication: the sender never declares, binds, or consumes the queue.

Change

  • RabbitMQDispatchEndpoint resolves its target by name. A queue or exchange that is part of the topology is provisioned according to its auto-provision setting, as before. Any other target is published to by name, to the default exchange with the queue name as routing key or to the named exchange, and is never declared, bound, or consumed. The endpoint exposes QueueName and ExchangeName; Queue, Exchange, and Destination stay unset for a target outside the topology.
  • RabbitMQMessagingTransport.TryGetDispatchEndpoint matches candidates by queue or exchange name instead of requiring Destination is RabbitMQQueue, so rabbitmq://host/vhost/q/name and queue:name resolve to the endpoint created from rabbitmq:q/name.
  • The topology address parser moved from RabbitMQRoutingStrategy to UriHelpers so both call sites share it.
  • DiscoverTopology and the explicit-mode guard are untouched. Nothing is added to the topology for an address-created endpoint.

Behavior change

The dispatch endpoint is no longer gated by the topology at all. A configured DispatchEndpoint("ep").ToQueue("name") under explicit binding no longer fails at startup when the queue is not declared; it publishes by name. As with every RabbitMQ publish, a message the broker cannot route is dropped. A mandatory/basic.return hardening and a passive existence check were evaluated and deliberately left out; neither Wolverine nor the rest of Mocha verifies destinations at send time.

Tests

  • RabbitMQDispatchEndpointTests: address-created endpoints for undeclared queues and exchanges, the topology staying empty, alias resolution across address forms, and a declared AutoProvision(false) queue still binding to its topology resource.
  • RabbitMQDispatchProvisioningTests: the publish goes to exchange "" with the queue name as routing key, and no declare is issued.
  • Behaviors/ExternalDestinationTests (real broker): a queue pre-created by another connection receives the send from a host that binds explicitly and declares nothing, and a send to a missing queue does not create it.

Docs

  • routing-and-endpoints.md: documents sends to queues outside the topology and fixes the address example, which used rabbitmq://custom-inventory-queue, a form no address parser accepts.
  • transports/rabbitmq.md: the page claimed dispatch uses publisher confirms. The transport never enabled them, so the paragraph now states the actual behavior.

Notes

  • The second commit fixes pre-existing IDE1006/IDE0059 errors in Mocha example projects that are not part of All.slnx. Drop it if you prefer a strictly focused PR.
  • The Azure Service Bus transport has the same gate for address-based sends under explicit binding; follow-up.

…t binding

Under BindExplicitly(), a send addressed by rabbitmq:q/<name> failed with
"Queue not found" unless the queue was declared in the sending host's
topology. The dispatch endpoint now resolves its target by name: a queue or
exchange that is part of the topology is provisioned per its auto-provision
setting, any other target is published to by name and never declared,
bound, or consumed. TryGetDispatchEndpoint matches candidates by queue or
exchange name, and the topology address parser moved to UriHelpers so both
call sites share it.
Static readonly fields in the Postgres examples lacked the s_ prefix and a
Demo.Shipping handler kept an unused assignment, which fails any build that
includes the example projects.
@github-actions github-actions Bot added 📚 documentation This issue is about working on our documentation. 🌶️ mocha labels Oct 5, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📚 documentation This issue is about working on our documentation. 🌶️ mocha

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant