docs/documentation/quartz-3.x/packages/redis.md
Quartz.Extensions.Redis provides a Redis-based distributed lock handler (ISemaphore) that replaces database row locks in clustered Quartz.NET setups.
::: tip Useful when database row locks (the default for clustered setups) cause deadlocks or performance issues under heavy scheduling load. :::
::: tip Quartz 3.18 or later required. :::
Install-Package Quartz.Extensions.Redis
The default StdRowLockSemaphore uses SELECT ... FOR UPDATE database row locks to coordinate trigger acquisition across cluster nodes. Under heavy scheduling load this can lead to:
QRTZ_LOCKS tableThe Redis lock handler replaces these database locks with Redis SET NX PX distributed locks while keeping all job and trigger data in your relational database.
var schedulerFactory = SchedulerBuilder.Create()
.UsePersistentStore(store =>
{
store.UseSqlServer(connectionString);
store.UseSystemTextJsonSerializer();
store.UseClustering();
store.UseRedisLockHandler(redis =>
{
redis.RedisConfiguration = "redis-server:6379";
});
})
.Build();
var properties = new NameValueCollection
{
["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
["quartz.jobStore.clustered"] = "true",
["quartz.jobStore.lockHandler.type"] = "Quartz.Impl.Redis.RedisSemaphore, Quartz.Extensions.Redis",
["quartz.jobStore.lockHandler.redisConfiguration"] = "redis-server:6379"
};
| Property | Default | Description |
|---|---|---|
redisConfiguration | localhost:6379 | StackExchange.Redis connection string |
keyPrefix | quartz:lock: | Prefix for Redis lock keys |
lockTtlMilliseconds | 30000 | Lock TTL in milliseconds (auto-expires after this duration) |
lockRetryIntervalMilliseconds | 100 | Polling interval between SET NX retry attempts |
All properties are set under quartz.jobStore.lockHandler.*. The schedName and tablePrefix properties are injected automatically.
The lock handler uses a two-tier locking strategy:
Local tier — A SemaphoreSlim per lock name prevents redundant Redis round-trips when the same process already holds the lock.
Redis tier — SET key value NX PX timeout provides the cross-node distributed lock. The key includes the scheduler name for multi-scheduler isolation (e.g., quartz:lock:MyScheduler:TRIGGER_ACCESS).
Lock release uses a Lua script for atomic check-and-delete, preventing a node from accidentally releasing a lock that has already expired and been re-acquired by another node.
ObtainLock throws a LockException which the scheduler handles via its standard retry mechanism.SET NX locks, not the Redlock algorithm. For most Quartz.NET deployments a single Redis instance (or replica set with Sentinel) is sufficient since the locks are advisory and short-lived.