OrionLock.Redis
3.0.0
dotnet add package OrionLock.Redis --version 3.0.0
NuGet\Install-Package OrionLock.Redis -Version 3.0.0
<PackageReference Include="OrionLock.Redis" Version="3.0.0" />
<PackageVersion Include="OrionLock.Redis" Version="3.0.0" />
<PackageReference Include="OrionLock.Redis" />
paket add OrionLock.Redis --version 3.0.0
#r "nuget: OrionLock.Redis, 3.0.0"
#:package OrionLock.Redis@3.0.0
#addin nuget:?package=OrionLock.Redis&version=3.0.0
#tool nuget:?package=OrionLock.Redis&version=3.0.0
OrionLock.Redis
Redis backend for OrionLock. SET NX PX acquire with owner-checked Lua compare-and-extend / compare-and-delete.
services.AddOrionLock().UseRedis("localhost:6379");
Which connection the locks use
UseRedis(connectionString) connects with that connection string, and keeps the resulting
multiplexer under a private DI key. Your application's own IConnectionMultiplexer — the one the cache
uses — is neither read nor replaced. (It used to be registered with TryAddSingleton, so an app that had
already registered one silently got its connection string discarded and locked against the cache's Redis
instead.)
UseRedis() with no connection string is the opt-in to sharing: it resolves the application's registered
IConnectionMultiplexer.
This package also ships the distributed reader-writer (shared/exclusive) lock. UseRedisSharedExclusive() registers ISharedExclusiveLock over Redis, additive to UseRedis():
services.AddOrionLock()
.UseRedis("localhost:6379")
.UseRedisSharedExclusive();
It keeps a Lua-scripted writer marker, a per-reader sorted set scored by lease expiry (so one reader's expiry never frees another's), and a lease-bounded pending-writer marker that holds off new readers so a waiting writer is not starved. All lease math uses the Redis server clock, and renew/release are owner-token checked.
Fencing tokens
Off by default. Turn it on and every acquire also returns a handle.FencingToken: an INCR on a per-key
counter issued in the same Lua call as the SET NX PX, so the token and the lock are taken atomically and
the number strictly increases per key across processes.
services.AddOrionLock().UseRedis("localhost:6379", o => o.FencingTokens = true);
It is opt-in because the counter key can never expire or be deleted — one that restarted would hand a
later holder a token an earlier one already spent — so enabling it leaves one small permanent
orionlock-fence:{key} key per lock key you take.
Counters live under that reserved orionlock-fence: prefix so no lock key can also be somebody's
counter; with fencing on, a lock key that would resolve into that namespace is rejected with an
ArgumentException. With the default orionlock: prefix the rejection can never fire. See the OrionLock
docs on fencing tokens for what to do with the number.
Lease durations
Both providers round a lease up to whole milliseconds, so the shortest lock you can take is 1 ms. A lease
of zero or less is rejected with ArgumentOutOfRangeException rather than accepted: PX 0 / PEXPIRE 0
does not mean "expire immediately" in Redis, it DELETES the key, which would drop the lock at its first
renewal.
Waiting subscribes, it does not poll
A contended waiter subscribes to a per-key release channel and parks instead of issuing a SET NX every
RetryInterval. A release publishes to that channel fire-and-forget, so waking every waiter on the key
costs the releasing caller no extra round trip, and a notification that cannot be delivered can never
fail a release.
A dedicated channel, not keyspace notifications. Keyspace notifications would need
notify-keyspace-events enabled on the server: it is off by default, a client library cannot turn it on,
and on a managed Redis it may not be configurable at all - a lock that silently never notified would be
worse than one that polls. The channel OrionLock publishes to itself works on any Redis, through a
replica or a proxy. There is no server-side configuration to do. The channel is
{KeyPrefix}{key}{ReleaseChannelSuffix}, default suffix :released.
What a channel cannot cover is a lock freed by TTL: a crashed holder publishes nothing. A waiter therefore also bounds its wait by the holder's remaining TTL, read once per wait rather than once per retry interval, so an expiry is still noticed promptly.
Set RedisLockOptions.UseReleaseNotifications = false on a deployment where pub/sub is unavailable or
undesirable; waiters then fall back to exactly the poll loop earlier releases used.
FIFO waiter fairness
RedisFifoWaiterCoordinator orders waiters by arrival millisecond, with a per-process sequence breaking
ties inside one millisecond. Two waiters in the same millisecond in different processes still fall
back to member ordering — cross-process sub-millisecond ordering is not a guarantee this coordinator
makes.
Requires the OrionLock package. See https://github.com/tunahanaliozturk/OrionLock.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- OrionLock (>= 3.0.0)
- StackExchange.Redis (>= 2.8.16)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- OrionLock (>= 3.0.0)
- StackExchange.Redis (>= 2.8.16)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- OrionLock (>= 3.0.0)
- StackExchange.Redis (>= 2.8.16)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on OrionLock.Redis:
| Package | Downloads |
|---|---|
|
OrionGuard.Locks.Redis
Redis-backed IDistributedLock for OrionGuard.EntityFrameworkCore's outbox dispatcher. Bridges OrionGuard's IDistributedLock contract to the OrionLock.Redis backend so multi-instance outbox workers can share a Redis-coordinated lease instead of the default SkipLocked DB lock. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0 | 93 | 9/20/2026 |
| 2.0.0 | 427 | 7/29/2026 |
| 1.0.1 | 122 | 7/27/2026 |
| 1.0.0 | 135 | 6/30/2026 |
| 0.6.0 | 126 | 6/27/2026 |
| 0.5.0 | 148 | 6/26/2026 |
| 0.4.1 | 136 | 6/20/2026 |
| 0.4.0 | 130 | 6/19/2026 |
| 0.3.32 | 156 | 6/17/2026 |
| 0.3.31 | 153 | 6/16/2026 |
| 0.3.30 | 164 | 6/16/2026 |
| 0.3.28 | 149 | 6/15/2026 |
| 0.3.27 | 162 | 6/15/2026 |
| 0.3.26 | 181 | 6/13/2026 |
| 0.3.25 | 186 | 6/13/2026 |
| 0.3.24 | 192 | 6/12/2026 |
| 0.3.23 | 199 | 6/12/2026 |
| 0.3.22 | 193 | 6/11/2026 |
| 0.3.21 | 194 | 6/11/2026 |
| 0.3.20 | 202 | 6/11/2026 |