Lyo.Lock.Redis
1.0.1
dotnet add package Lyo.Lock.Redis --version 1.0.1
NuGet\Install-Package Lyo.Lock.Redis -Version 1.0.1
<PackageReference Include="Lyo.Lock.Redis" Version="1.0.1" />
<PackageVersion Include="Lyo.Lock.Redis" Version="1.0.1" />
<PackageReference Include="Lyo.Lock.Redis" />
paket add Lyo.Lock.Redis --version 1.0.1
#r "nuget: Lyo.Lock.Redis, 1.0.1"
#:package Lyo.Lock.Redis@1.0.1
#addin nuget:?package=Lyo.Lock.Redis&version=1.0.1
#tool nuget:?package=Lyo.Lock.Redis&version=1.0.1
Lyo.Lock.Redis
Distributed implementation of ILockService using Redis and StackExchange.Redis. Use this when multiple app instances must exclude each other on the same logical key.
Keyed semaphores (IKeyedSemaphoreService) are not implemented here; they remain in-process in Lyo.Lock.
Features
- Cross-process / cross-host mutual exclusion on string keys.
- Acquire —
SET key token NX PX ttl(unique token per holder). - Release — Lua script deletes the key only if the value still matches the token (avoids deleting another instance’s lock after expiry or misuse).
- Waiting — optional pub/sub wakeups on release (
UsePubSubForAcquireWait) to avoid sleeping on a fixed poll interval; fallback polling usesAcquirePollInterval. - TTL —
DefaultLockDuration/ per-calllockDurationso crashed processes do not hold keys forever. - Shared multiplexer — use the same
IConnectionMultiplexeras caching or other Redis consumers.
Examples
Existing 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;
});
Connection string
services.AddRedisLock("localhost:6379", options =>
{
options.AcquirePollInterval = TimeSpan.FromMilliseconds(10);
});
Configuration
services.AddRedisLockFromConfiguration(configuration);
Configuration (2)
services.AddRedisLockFromConfiguration(configuration, redisSectionName: "RedisCluster");
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
}
}
Connection string
Registers IConnectionMultiplexer with TryAddSingleton if missing, then the lock service:
Configuration
Binds LockOptions from the LockOptions section and reads Redis from the Redis section (ConnectionString, optional Password): Custom Redis section name: Throws ConfigurationException (from Lyo.Exceptions) if no connection string can be resolved. Example appsettings.json:
RedisLockOptions (extends LockOptions)
| Property | Default | Description |
|---|---|---|
AcquirePollInterval |
10 ms | Delay between retries when UsePubSubForAcquireWait is false. |
UsePubSubForAcquireWait |
true |
Subscribe to a per-key notify channel while waiting; publisher runs on successful Lua delete in ReleaseAsync. |
Inherited from LockOptions: DefaultAcquireTimeout, DefaultLockDuration, KeyPrefix, EnableMetrics, SkipKeyNormalization.
How it works
- Redis key —
KeyPrefix+ normalized logical key (unless normalization is skipped). - Acquire loop — try
SETwithNXand expiry; on failure, either wait on pub/sub with bounded deadline orTask.Delay(AcquirePollInterval). - Notify channel — separate Redis channel derived from the same prefix and key so waiters can retry promptly after a legitimate release.
- Release — Lua compares stored token to holder’s token; if equal,
DELand publish to the notify channel.
Operational notes
- TTL vs work duration — if your critical section can run longer than
lockDuration, the key may expire and another instance can acquire. SizeDefaultLockDuration/ per-calllockDurationabove worst-case runtime, or shorten the guarded work. - Clocks — acquire timeout uses
DateTime.UtcNowon the client for deadline calculation; Redis handles key TTL independently. - Fairness — 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.Configuration.Binder10.0.5— (direct, microsoft)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)Microsoft.Extensions.Options.ConfigurationExtensions10.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 (>= 1.0.1)
- Lyo.Lock (>= 1.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 (>= 1.0.1)
- Lyo.Lock (>= 1.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.