feat(rabbitmq): public API for multi-node cluster endpoints (#2659)#2664
Merged
jeremydmiller merged 1 commit intoJasperFx:mainfrom May 4, 2026
Merged
Conversation
…#2659) Expose AddClusterNode(host, port) and AddClusterNode(AmqpTcpEndpoint) on RabbitMqTransportExpression so applications can configure RabbitMQ cluster failover via the fluent API. The underlying connection plumbing (RabbitMqTransport.AmqpTcpEndpoints + ConnectionFactory.CreateConnectionAsync(endpoints)) already existed but had no public entry point. - (host, port) overload copies ConnectionFactory.Ssl onto the new endpoint as a fresh SslOption so TLS configured on the factory applies to cluster nodes by default. - (AmqpTcpEndpoint) overload stores the supplied endpoint as-is for full per-node control. - Both overloads require UseRabbitMq(...) or UseRabbitMqUsingNamedConnection(...) to have run first; the error message names both entry points. - Virtual-host tenants inherit the parent transport's cluster nodes via RabbitMqTenant.Compile(), guarded against duplicate appends on repeated Compile() calls. URI- and Action-based tenants do not inherit (documented limitation). - RabbitMqConnectionDescription gains indexed ClusterNodes[i] entries so the cluster configuration is visible in diagnostics. ResourceUri and health-check semantics are unchanged. - Docs: new "Connecting to a RabbitMQ cluster" section in the RabbitMQ guide with TLS-inheritance and per-node override examples plus the documented tenant-inheritance rule and rationale.
jeremydmiller
added a commit
that referenced
this pull request
May 4, 2026
Minor release. Highlights: - WolverineFx.Marten: durable local messages routed by the receiving handler's ancillary store (Uri-based gate, no IMessageStore.Id dependency). Closes #2669. PR #2674. - WolverineFx.RabbitMQ: public AddClusterNode(...) API for multi-node failover. Closes #2659. PR #2664. - WolverineFx.Polecat: fixed NRE in OutboxedSessionFactory when constructing the FlushOutgoingMessagesOnCommit listener. Closes #2668. PR #2672. - WolverineFx core: new DocumentStores collection on ServiceCapabilities for CritterWatch document-side rendering. - Dependency bumps: JasperFx 1.28.2 → 1.29.0, JasperFx.Events 1.31.1 → 1.33.1, Marten + Marten.AspNetCore 8.32.0 → 8.35.0. Also backfilled a 5.36.2 entry in CHANGELOG covering the EF Core + outbox flush rework from PR #2665 that landed without a CHANGELOG note at the time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 4, 2026
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.
Summary
Adds public fluent API for RabbitMQ multi-node cluster failover. Closes #2659.
Wolverine's RabbitMQ transport already had the internal plumbing —
RabbitMqTransport.AmqpTcpEndpointsis forwarded toConnectionFactory.CreateConnectionAsync(IList<AmqpTcpEndpoint>)(the official RabbitMQ.NET client failover API) — but no public way to populate the list. This PR exposes that capability throughRabbitMqTransportExpression, propagates the configuration to virtual-host tenants, and surfaces the cluster nodes in connection diagnostics.Public API
Two repeatable overloads on
RabbitMqTransportExpression:AddClusterNode(string hostName, int port = -1)— convenience overload. CopiesConnectionFactory.Sslonto the new endpoint as a freshSslOptionso TLS configured on the factory applies to all cluster nodes by default.port = -1defers to theAmqpTcpEndpointconstructor (5672 normal, 5671 TLS).AddClusterNode(AmqpTcpEndpoint endpoint)— power-user overload. Stores the supplied endpoint as-is. Use this for per-node TLS, distinct certificates, or non-default ports.Both overloads require
UseRabbitMq(...)orUseRabbitMqUsingNamedConnection(...)to have run first; a clearInvalidOperationExceptionnames both entry points.Multi-tenancy
Virtual-host tenants (
AddTenant(tenantId, virtualHostName)) inherit the parent transport's cluster nodes automatically — they target the same broker, so they should sharethe cluster topology.
URI- and Action-based tenants (
AddTenant(tenantId, Uri),AddTenant(tenantId, Action<ConnectionFactory>)) do not inherit the parent cluster — those overloads are for tenants on separate brokers and bring their own connection settings. This is a documented limitation; a future overload could accept cluster nodes for those paths if requested.RabbitMqTenant.Compile()is guarded against duplicate appends on repeated calls.Diagnostics
RabbitMqConnectionDescriptiongains indexedClusterNodes[i]entries (formattedhost:port) so the cluster configuration is visible in logs, resource reports, andOptionsDescriptionconsumers.ResourceUriandRabbitMqHealthChecksemantics are unchanged — by design, since cluster failover means "any reachable node = healthy", not "all nodes individually reachable".Out of scope
ConnectionStringParser). Deferred until concrete demand and a clear format convention emerge. The fluent API is the only entry point for now.Test plan
port = -1default resolution, ordered append,AmqpTcpEndpointoverload preserves reference equality.Compile()is idempotent.ClusterNodes[i]entries render only when configured; empty list produces no entries., verifies traffic flows through CreateConnectionAsync(IList<AmqpTcpEndpoint>).