Skip to content

GH-3110: Redis transport supports caller-managed ConnectionMultiplexer / ConfigurationOptions#3114

Merged
jeremydmiller merged 2 commits into
mainfrom
feature-3110-redis-connection-multiplexer
Jun 15, 2026
Merged

GH-3110: Redis transport supports caller-managed ConnectionMultiplexer / ConfigurationOptions#3114
jeremydmiller merged 2 commits into
mainfrom
feature-3110-redis-connection-multiplexer

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3110.

Problem

Wolverine.Redis could only be configured with a connection string, so it always created and owned the ConnectionMultiplexer internally. That blocks token-based auth — Azure Managed Redis with Entra ID / Managed Identity (via Microsoft.Azure.StackExchangeRedis) — because when an access token expires the app must be restarted; the underlying multiplexer can be neither replaced nor reconfigured.

Approach (modeled on the Azure Service Bus transport)

ASB supports several construction modes (UseAzureServiceBus(connectionString), UseAzureServiceBus(namespace, TokenCredential), ...) by storing whichever inputs were supplied and building one client from them. This PR gives Redis the same shape — two new UseRedisTransport overloads matching the exact API requested in the issue:

opts.UseRedisTransport(ConfigurationOptions options);       // Wolverine builds & owns the multiplexer
opts.UseRedisTransport(IConnectionMultiplexer multiplexer); // caller-managed; Wolverine never disposes it

RedisTransport now holds exactly one of three connection sources (caller-managed multiplexer > ConfigurationOptions > connection string) and resolves a single shared connection lazily from it. Key behaviors:

  • A caller-managed IConnectionMultiplexer is used as-is and is never disposed on shutdown — the caller owns its lifetime and any token-refresh background work. The connection-string / ConfigurationOptions multiplexers are still owned and disposed by Wolverine.
  • ResourceUri, ConnectionSummary, and connect-logging derive from whichever source is configured; passwords are masked (and a caller-managed multiplexer is reported as such, since Wolverine never sees its credentials).
  • The existing connection-string overload and behavior are unchanged.

Why this solves token refresh

With ConfigurationOptions or a caller-managed multiplexer, Wolverine never has to recreate the connection from a static connection string, so Microsoft.Azure.StackExchangeRedis can refresh the Entra token in place — no pod restart on expiry.

Tests

redis_connection_source_configuration covers all three modes: caller-managed multiplexer reused and never closed/disposed, password masking for connection string + ConfigurationOptions, ConfigurationOptions building a working connection, and an end-to-end round-trip with a caller-managed multiplexer that survives host disposal. Existing pub/sub + diagnostics + non-default-database tests still pass.

Docs

Adds a Connection Options section to the Redis transport guide, including the Azure Managed Redis / Entra ID example.

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits June 15, 2026 12:10
…r / ConfigurationOptions

The Redis transport could only be configured with a connection string, so it always created and
owned the ConnectionMultiplexer internally. That made token-based auth (Azure Managed Redis with
Entra ID / Managed Identity, via Microsoft.Azure.StackExchangeRedis) impossible — when a token
expired the app had to be restarted, since the underlying multiplexer could neither be replaced
nor reconfigured.

Add two more connection sources, modeled on the Azure Service Bus transport's
"one client, several construction modes" pattern:

  opts.UseRedisTransport(ConfigurationOptions options);     // Wolverine builds/owns the multiplexer
  opts.UseRedisTransport(IConnectionMultiplexer multiplexer); // caller-managed; Wolverine never disposes it

RedisTransport now holds exactly one of three sources (external multiplexer > ConfigurationOptions >
connection string) and resolves a single shared connection lazily from it. A caller-managed
multiplexer is used as-is and is NOT disposed on shutdown (the caller owns its lifetime and any
token-refresh wired into it); ResourceUri / ConnectionSummary / connect-logging derive from whichever
source is configured, with passwords masked.

Tests cover all three modes: caller-managed multiplexer reused and never disposed, password masking,
ConfigurationOptions building a working connection, and an end-to-end round-trip with a caller-managed
multiplexer that survives host disposal. Docs add a "Connection Options" section with the Azure
Managed Redis / Entra ID example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iplexer>) overload

Lets the Redis transport share an IConnectionMultiplexer resolved from the application's IoC
container, so one multiplexer (e.g. a singleton wired with Microsoft.Azure.StackExchangeRedis token
refresh) can be reused by Wolverine and the rest of the app. The factory is resolved against
runtime.Services during ConnectAsync (which runs before any endpoint forces a connection). Like the
caller-managed IConnectionMultiplexer overload, a factory-resolved multiplexer is assumed to be owned
by the container and is never disposed by Wolverine.

Tests cover the factory round-tripping end to end, resolving the multiplexer from the container
(same-instance), not being disposed by Wolverine, and the connection-summary rendering. Docs updated
with the fourth connection option.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 793b02f into main Jun 15, 2026
23 checks passed
This was referenced Jun 15, 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 Transport: Support caller-managed ConnectionMultiplexer / ConfigurationOptions for token-based authentication

1 participant