Redis Transport 4.4.0
4.4.0 of the Redis transport is out. Its main feature is automatic pruning of idle subscriptions, aimed squarely at cloud and container deployments where instance names never stay still.
What changed
Every event subscriber gets its own per-instance queue in Redis, keyed off the instance name you pass to WithNames. That’s fine for a fixed set of long-lived hosts, but it’s a problem for anything running on Kubernetes, ECS, or similar — pod and task names are freshly generated on every deploy, restart, or scale event, so each one is effectively a new, permanent subscriber as far as Redis is concerned. The old instance never comes back to unsubscribe; it’s just gone. Redeploy a service a few times a day and you’re leaking a queue and a subscription entry every time, forever. With Redis, this eventually leads to OOM errors which stop you from sending any more messages.
4.4.0 adds a heartbeat: each subscriber refreshes a liveness key in Redis on a timer while its instance is running. Two mechanisms use that heartbeat to prune dead subscriptions:
- Prune-on-send. When a topic sender is about to deliver a message, it checks the subscriber’s liveness key first. If it’s expired, the sender removes the subscription and its queue on the spot instead of writing into it.
- Idle subscription reaper. A background sweep catches the case prune-on-send can’t reach — a topic nobody is publishing to any more. It periodically scans subscription sets for entries whose liveness key has lapsed and removes them, running several sweeps per TTL window so a slow or missed sweep doesn’t let a dead entry linger.
Together these mean an instance that goes away without unsubscribing — whether it crashed or was simply replaced by a redeploy under a new pod name — gets cleaned up automatically, typically well within one AutoDeleteOnIdle window.
Configuring the idle window
The cleanup window is configurable and defaults to 4 days, with a 5 minute minimum:
var bus = new BusBuilder()
.Configure()
.WithNames("OrderService", Environment.MachineName)
.WithTransport(new RedisTransportConfiguration().WithConnectionString("localhost:6379"))
.WithAutoDeleteOnIdle(TimeSpan.FromDays(1)) // Optional, defaults to 4 days, minimum 5 minutes
.WithTypesFrom(typeProvider)
.WithAutofacDefaults(container)
.Build();
A running instance keeps its own heartbeat refreshed regardless of message traffic, so an idle topic won’t trigger cleanup on its own — the window only matters once an instance actually stops. If your deploys are frequent and pods rarely pause without being torn down, it’s safe to pull WithAutoDeleteOnIdle in well below the 4 day default so orphaned queues from old pod names clear out faster. If instead you rely on instances going quiet for extended periods and resuming later under the same name, raise it instead; the default assumes an instance that stops is gone for good, and any messages published to its subscription are lost once the window elapses.
See the Redis transport docs for the full details.
Upgrading
dotnet add package Nimbus.Transports.Redis --version 4.4.0
No breaking changes. WithAutoDeleteOnIdle is optional — existing configurations pick up the 4 day default automatically.