Lyo.Lock.Redis
2.0.1
dotnet add package Lyo.Lock.Redis --version 2.0.1
NuGet\Install-Package Lyo.Lock.Redis -Version 2.0.1
<PackageReference Include="Lyo.Lock.Redis" Version="2.0.1" />
<PackageVersion Include="Lyo.Lock.Redis" Version="2.0.1" />
<PackageReference Include="Lyo.Lock.Redis" />
paket add Lyo.Lock.Redis --version 2.0.1
#r "nuget: Lyo.Lock.Redis, 2.0.1"
#:package Lyo.Lock.Redis@2.0.1
#addin nuget:?package=Lyo.Lock.Redis&version=2.0.1
#tool nuget:?package=Lyo.Lock.Redis&version=2.0.1
Lyo.Lock.Redis
Redis-backed ILockService through StackExchange.Redis. Reach for this when several app instances must exclude each other on one logical key.
Keyed semaphores (IKeyedSemaphoreService) are not implemented here. They stay in-process in Lyo.Lock.
Features
- Cross-process / cross-host. String keys for mutual exclusion.
- Acquire.
SET key token NX PX ttl(one unique token per holder). - Release. A Lua script deletes the key only while the stored value still matches the token (so another instance's lock is not deleted after expiry or misuse).
- Waiting. Optional pub/sub wakeups on release (
UsePubSubForAcquireWait) so waiters are not stuck on a fixed poll interval. Fallback polling usesAcquirePollInterval. - TTL.
DefaultLockDuration/ per-calllockDurationso a crashed process cannot hold a key forever. - Shared multiplexer. Reuse the same
IConnectionMultiplexeras caching or other Redis consumers.
Examples
Reuse an IConnectionMultiplexer
using Lyo.Lock.Redis;
using Microsoft.Extensions.DependencyInjection;
// IConnectionMultiplexer must already be registered (e.g. shared cache setup)
services.AddRedisLock(options =>
{
options.DefaultAcquireTimeout = TimeSpan.FromSeconds(30);
options.DefaultLockDuration = TimeSpan.FromSeconds(60);
options.UsePubSubForAcquireWait = true;
});
From a connection string
services.AddRedisLock("localhost:6379", options =>
{
options.AcquirePollInterval = TimeSpan.FromMilliseconds(10);
});
From configuration
services.AddRedisLockFromConfiguration(configuration);
From configuration (2)
services.AddRedisLockFromConfiguration(configuration, redisSectionName: "RedisCluster");
From configuration (3)
{
"Redis": {
"ConnectionString": "localhost:6379",
"Password": "optional-password"
},
"LockOptions": {
"DefaultAcquireTimeout": "00:00:30",
"DefaultLockDuration": "00:01:00",
"KeyPrefix": "lyo:lock:",
"AcquirePollInterval": "00:00:00.010",
"UsePubSubForAcquireWait": true,
"EnableMetrics": false,
"SkipKeyNormalization": false
}
}
From a connection string
Registers IConnectionMultiplexer with TryAddSingleton if it is missing, then the lock service:
From configuration
Binds LockOptions from the LockOptions section and reads Redis from the Redis section (ConnectionString, optional Password). A custom Redis section name throws ConfigurationException (from Lyo.Exceptions) if no connection string can be resolved. Example appsettings.json:
RedisLockOptions (builds on LockOptions)
| Property | Default | What it controls |
|---|---|---|
AcquirePollInterval |
10 ms | Retry delay when UsePubSubForAcquireWait is false. |
UsePubSubForAcquireWait |
true |
While waiting, subscribe to a per-key notify channel. A successful Lua delete in ReleaseAsync publishes. |
From LockOptions: DefaultLockDuration, DefaultAcquireTimeout, KeyPrefix, EnableMetrics, SkipKeyNormalization.
Internals
- Redis key. The normalized logical key plus
KeyPrefix(unless normalization is skipped). - Acquire loop. Attempt
SETwithNXand expiry. On failure, wait on pub/sub with a bounded deadline, orTask.Delay(AcquirePollInterval). - Notify channel. A separate Redis channel from the same prefix and key so waiters can retry promptly after a legitimate release.
- Release. Lua compares the holder's token to the stored token. On match,
DELand publish to the notify channel.
Ops notes
- TTL vs work duration. Another instance can acquire if the key expires while the critical section still runs longer than
lockDuration. SizeDefaultLockDuration/ per-calllockDurationabove worst-case runtime, or shorten the guarded work. - Clocks. The client deadline uses
DateTime.UtcNowfor acquire timeout. Redis handles key TTL independently. - Fairness. These Redis locks are not strictly FIFO. Under contention, which waiter wins is nondeterministic.
- Metrics. Same names as
Lyo.Lock.Constants.MetricswhenEnableMetricsis true (seeLyo.LockREADME).
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Exceptions(direct, lyo)Lyo.Lock(direct, lyo)Microsoft.Extensions.DependencyInjection10.0.5(direct, microsoft)Microsoft.Extensions.Logging.Abstractions10.0.5(direct, microsoft)StackExchange.Redis2.12.0(direct, third-party)Lyo.Metrics(transitive, lyo)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5(transitive, microsoft)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Lyo.Exceptions (>= 2.0.0)
- Lyo.Lock (>= 2.0.1)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- StackExchange.Redis (>= 2.12.0 && < 3.0.0)
-
net10.0
- Lyo.Exceptions (>= 2.0.0)
- Lyo.Lock (>= 2.0.1)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- StackExchange.Redis (>= 2.12.0 && < 3.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.