Skip to content

feat(redis): named-broker and broker-per-tenant support (GH-3309)#3321

Merged
jeremydmiller merged 1 commit into
mainfrom
feat/redis-named-and-tenant-3309
Jul 6, 2026
Merged

feat(redis): named-broker and broker-per-tenant support (GH-3309)#3321
jeremydmiller merged 1 commit into
mainfrom
feat/redis-named-and-tenant-3309

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3309

Brings the Redis Streams transport (Wolverine.Redis) up to parity with RabbitMQ / NATS on the two established multi-broker features. It had neither before.

Feature 1 — Named broker

  • RedisTransport now stores an instance Protocol (heaviest part of this change): protocol-carrying constructors for every connection source, and all endpoint-URI construction + scheme checks (buildStreamCache, ResourceUri, findEndpointByUri, tryBuildSystemEndpoints, RedisHealthCheck) use it instead of the hard-coded "redis" literal. A named broker's endpoints therefore carry the broker name as their URI scheme (secondary://stream/0/orders) and never collide with the default redis:// broker.
  • AddNamedRedisBroker(BrokerName, …) with connection-string / ConfigurationOptions / IConnectionMultiplexer / factory overloads. Because Redis needs connection info, it constructs new RedisTransport(name.Name, …) and Transports.Add(...) directly rather than relying on GetOrCreate's reflective ctor.
  • ListenToRedisStreamOnNamedBroker / ToRedisStreamOnNamedBroker pin endpoints to a named broker (throws a helpful error if the broker wasn't registered first).

Feature 2 — Broker-per-tenant (modeled after NATS)

  • New RedisTenant — a dedicated, lazily-built IConnectionMultiplexer per tenant (connection string / ConfigurationOptions / caller-managed multiplexer). RedisTransport.Tenants + GetTenantConnection; eager connect+ping in ConnectAsync; disposal in DisposeAsync of only the multiplexers Wolverine built itself.
  • AddTenant(tenantId, …) + ConfigureMultiTenancy(TenantedIdBehavior) on the expression.
  • CreateSender fans out to a framework TenantedSender, routed by Envelope.TenantId; BuildListenerAsync builds a CompoundListener with one listener per dedicated-connection tenant wrapped in ReceiverWithRules + TenantIdRule. The sender/listener take an optional tenant multiplexer and target their own database on it. Tenant listeners provision their consumer group on their own server.

GH-2361

Both the tenant senders and the default fallback under TenantedSender are the fire-and-forget InlineRedisStreamSendernot BatchedSender + RedisSenderProtocol. TenantedSender doesn't forward RegisterCallback, so a callback-requiring sender under it would silently drop every message. Verified by the inbound tenant round-trip test (a silent drop would surface as a timeout).

Tests

  • RedisNamedBrokerRegistrationTests (no broker; always runs in CI) — distinct transport per broker, endpoints use the broker name as scheme, unregistered-broker throws.
  • RedisNamedBrokerTests + RedisPerTenantConnectionTests — spin up a second Redis container (server B) via a shared IClassFixture; raw XREAD proves a …OnNamedBroker / TenantId-tagged message lands on server B (and a default on server A), plus an inbound round-trip stamped with the broker scheme / tenant id.
  • Full Wolverine.Redis.Tests green (131 passed). dotnet build wolverine.slnx -c Release clean (0 warnings, 0 errors).

Docs

Added "Connecting to Multiple Brokers" and "Multi-Tenancy" sections to docs/guide/messaging/transports/redis.md with compiling snippet samples; reverted unrelated mdsnippets churn.

Caveats

  • Each tenant is an independent Redis server, so the same stream key + consumer group are created separately per tenant multiplexer — no collision (dedicated multiplexer per tenant is the spec, not shared-server-different-DB).
  • The two integration test classes need a second Redis container, so they skip cleanly when Docker is unavailable.

🤖 Generated with Claude Code

Bring the Redis Streams transport up to parity with RabbitMQ / NATS on the
two established multi-broker features.

Named broker:
- Add protocol-carrying constructors for each connection source; endpoint URIs
  and scheme checks now use the instance Protocol instead of the hard-coded
  "redis" literal, so a named broker's endpoints use the broker name as their
  URI scheme and never collide with the default redis:// broker.
- AddNamedRedisBroker (connection string / ConfigurationOptions /
  IConnectionMultiplexer / factory overloads) constructs a distinct
  RedisTransport keyed by Protocol; ListenToRedisStreamOnNamedBroker /
  ToRedisStreamOnNamedBroker pin endpoints to it.

Broker-per-tenant:
- New RedisTenant (dedicated, lazily-built IConnectionMultiplexer per tenant);
  RedisTransport.Tenants + GetTenantConnection; eager connect/ping in
  ConnectAsync; disposal of Wolverine-built tenant multiplexers only.
- AddTenant + ConfigureMultiTenancy on the expression.
- CreateSender fans out to a TenantedSender of inline senders (never a
  BatchedSender under TenantedSender — GH-2361); BuildListenerAsync builds a
  CompoundListener with one listener per dedicated-connection tenant wrapped in
  ReceiverWithRules + TenantIdRule. Sender/listener take an optional tenant
  multiplexer and target their own database on it; tenant listeners provision
  their consumer group on their own server.

Tests: RedisNamedBrokerTests (registration + two-container send/round-trip) and
RedisPerTenantConnectionTests (tenant vs default server + inbound tenant stamp),
using a shared second-Redis-server class fixture and raw XREAD to prove the
exact target server. Docs: named-broker + multi-tenancy sections in redis.md.
Full Wolverine.Redis.Tests green (131); wolverine.slnx Release clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller marked this pull request as ready for review July 6, 2026 11:01
@jeremydmiller
jeremydmiller merged commit dbdc1c9 into main Jul 6, 2026
25 checks passed
This was referenced Jul 9, 2026
This was referenced Jul 14, 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.

Redis: add named-broker and broker-per-tenant support

1 participant