feat(nats): add named-broker support (GH-3310)#3314
Merged
Conversation
Bring the NATS transport to parity with RabbitMQ/Kafka/SQS/Azure on the "named broker" feature so a single application can address multiple independent NATS brokers, each pinnable via *OnNamedBroker overloads. - Add a NatsTransport(string protocol) constructor so the transport can be created through TransportCollection.GetOrCreate<T>(BrokerName). A named broker's Protocol doubles as its endpoints' URI scheme. - Build endpoint URIs and inbound envelope Destination/ReplyUri from the transport's Protocol instead of a hard-coded "nats" literal, so a named broker's endpoints never collide with the default nats:// broker and reply/tracking routing resolves back to the right transport instance. - Relax NatsTransport.ExtractSubjectFromUri: the scheme is no longer validated against a fixed literal (named brokers carry the broker name as the scheme; routing by scheme already happened upstream). - NatsHealthCheck.Protocol now reflects the transport's Protocol. - New extension methods: AddNamedNatsBroker (connection-string and Action<NatsTransportConfiguration> overloads), ToNatsSubjectOnNamedBroker, ListenToNatsSubjectOnNamedBroker. Tests: 3 CI-safe registration/URI tests + 3 integration tests that spin up a second broker via Testcontainers proving a named send lands on the named broker (not the default), a default send lands on the default (not the named), and a round-trip over the named broker stamps the broker's scheme. Full Wolverine.Nats suite green (144). Docs: new "Connecting to Multiple NATS Brokers" section in nats.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…est/reply test Addresses review feedback questioning whether the NatsEnvelopeMapper scheme change was necessary. It was not: on a received message the pipeline already sets the correct scheme without touching the mapper. - Envelope.MarkReceived sets Destination from the listener endpoint's URI (NatsListener.Address = NatsEndpoint.Uri), which already carries the named broker's scheme via the NatsEndpoint(protocol) constructor change. - MessageContext.ReadEnvelope calls MaybeCorrectReplyUri, which rewrites the reply-uri's scheme to match Destination.Scheme (JasperFx MaybeCorrectScheme unconditionally swaps the scheme). MarkReceived runs before ReadEnvelope, so by then Destination already has the named broker's scheme. So reverting NatsEnvelopeMapper/JetStreamEnvelopeMapper back to the canonical nats:// form is correct — the endpoint-URI scheme is the single source of truth and the pipeline propagates it to Destination and the reply-uri. Adds request_reply_round_trips_over_the_named_broker: a full InvokeAndWaitAsync over the named broker. If reply routing resolved to the default broker instead of the named one, this would time out — so it proves the reply travels back over the named broker with the mapper untouched.
Member
Author
|
Re: whether the inbound envelope-mapper scheme change was necessary — it wasn't, so I dropped it ( Trace of why the endpoint-URI change alone is sufficient:
So the endpoint URI is the single source of truth and the pipeline propagates it to both Added |
jeremydmiller
marked this pull request as ready for review
July 6, 2026 11:01
This was referenced Jul 9, 2026
Merged
This was referenced Jul 14, 2026
Open
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 #3310.
First of the transport multi-broker parity sweep (issues #3303–#3310, seeded by NATS #3283). Brings the NATS transport to parity with RabbitMQ/Kafka/SQS/Azure on the named broker feature: a single application can address multiple independent NATS brokers, each pinnable via
*OnNamedBrokeroverloads.Changes
NatsTransport(string protocol)constructor so the transport can be created throughTransportCollection.GetOrCreate<T>(BrokerName). A named broker'sProtocoldoubles as its endpoints' URI scheme. The parameterless ctor delegates to it withProtocolName("nats"), unchanged behavior for the default broker.NatsEndpoint) and inbound envelopeDestination/ReplyUri(NatsEnvelopeMapper+JetStreamEnvelopeMapper) are now built from the transport'sProtocolinstead of a hard-coded"nats"literal, so a named broker's endpoints never collide with the defaultnats://broker and reply/tracking routing resolves back to the right transport instance.ExtractSubjectFromUri: the scheme is no longer validated against a fixed literal (named brokers carry the broker name as the scheme; routing to the correct transport already happens by scheme upstream).NatsHealthCheck.Protocolnow reflects the transport'sProtocol.AddNamedNatsBroker(connection-string andAction<NatsTransportConfiguration>overloads),ToNatsSubjectOnNamedBroker,ListenToNatsSubjectOnNamedBroker.Tests
Wolverine.Nats.Tests— full suite green (144 on net9.0):NatsNamedBrokerRegistrationTests, no broker): distinct transport instance per broker, named-broker endpoints use the broker name as their URI scheme, config-action overload applies to the named broker only.NatsNamedBrokerTests, spins a second broker via Testcontainers, mirrorsNatsPerTenantConnectionTests): a named send lands on the named broker and not the default; a default send lands on the default and not the named; a round-trip over the named broker arrives stamped with the broker's scheme (exercises the inbound mapper change).Docs
New "Connecting to Multiple NATS Brokers" section in
docs/guide/messaging/transports/nats.md, contrasting named brokers (static, explicitly targeted) with per-tenant connections (runtime tenant-id selection).Build
dotnet build wolverine.slnx -c Release— 0 errors.🤖 Generated with Claude Code