Configuration
Redis connection options and multi-node heartbeat settings.
TickerQRedisOptionBuilder extends RedisCacheOptions from Microsoft.Extensions.Caching.StackExchangeRedis, so all standard Redis cache options are available.
Options
| Property | Default | Description |
|---|---|---|
Configuration | — | Redis connection string (e.g. "localhost:6379") |
ConfigurationOptions | — | StackExchange.Redis ConfigurationOptions object |
ConnectionMultiplexer | — | Pre-built IConnectionMultiplexer; takes priority over all other connection options |
InstanceName | "tickerq:" | Key prefix for IDistributedCache entries |
NodeHeartbeatInterval | 1 minute | How often this node sends a heartbeat |
Connection string
opt.AddStackExchangeRedis(redis =>
{
redis.Configuration = "redis-server:6379,password=secret,ssl=true";
});ConfigurationOptions
For advanced scenarios, use the StackExchange.Redis configuration object:
opt.AddStackExchangeRedis(redis =>
{
redis.ConfigurationOptions = new ConfigurationOptions
{
EndPoints = { "redis-primary:6379", "redis-replica:6379" },
Password = "secret",
Ssl = true,
AbortOnConnectFail = false,
ConnectTimeout = 5000,
};
});Passing an existing multiplexer
If you already have an IConnectionMultiplexer instance, assign it directly so TickerQ reuses the same connection instead of opening a new one:
builder.Services.AddSingleton<IConnectionMultiplexer>(_ =>
ConnectionMultiplexer.Connect("localhost:6379"));
builder.Services.AddTickerQ((sp, opt) =>
{
opt.AddStackExchangeRedis(redis =>
{
redis.ConnectionMultiplexer = sp.GetRequiredService<IConnectionMultiplexer>();
});
});Using a factory
If your multiplexer is created asynchronously (e.g. via an async factory), use the ConnectionMultiplexerFactory property inherited from RedisCacheOptions. TickerQ invokes the factory once when the singleton is first resolved and caches the result:
builder.Services.AddTickerQ((sp, opt) =>
{
opt.AddStackExchangeRedis(redis =>
{
redis.ConnectionMultiplexerFactory = async () => await ConnectionMultiplexer.ConnectAsync("localhost:6379");
});
});Connection precedence (first match wins): ConnectionMultiplexer → ConnectionMultiplexerFactory → ConfigurationOptions → Configuration.
DI isolation
TickerQ registers its own IConnectionMultiplexer and IDatabase under the keyed DI key "tickerq". This means:
- The host application's unkeyed
IConnectionMultiplexerregistration is never modified or replaced. - TickerQ always resolves its own connection through the
"tickerq"key regardless of what else is in the DI container. - Sharing is explicit opt-in: pass your multiplexer via
redis.ConnectionMultiplexerand TickerQ will register that instance under its own key.
// Host app — unkeyed slot, owned by the host
services.AddSingleton<IConnectionMultiplexer>(myMultiplexer);
// TickerQ — keyed slot "tickerq", completely independent
services.AddTickerQ(opt =>
opt.AddStackExchangeRedis(redis => redis.Configuration = "localhost:6379"));
// Both coexist without conflict
var hostMultiplexer = sp.GetRequiredService<IConnectionMultiplexer>(); // myMultiplexer
var tickerMultiplexer = sp.GetRequiredKeyedService<IConnectionMultiplexer>("tickerq"); // TickerQ's ownHeartbeat interval
Each node writes a hb:<node> key with a TTL of interval + 20 seconds. Other nodes detect a node as dead when its heartbeat key expires.
opt.AddStackExchangeRedis(redis =>
{
redis.Configuration = "localhost:6379";
redis.NodeHeartbeatInterval = TimeSpan.FromSeconds(30); // more aggressive detection
});Multi-node lifecycle
- Startup — node sends an initial heartbeat and registers in
nodes:registry - Every interval — node checks for dead nodes, recovers their locked jobs, then sends a fresh heartbeat
- Dead-node recovery — Lua script atomically clears
LockHolder, sets status toIdle, and re-queues the job - Shutdown — heartbeat key expires after TTL, other nodes detect and recover resources