GM.DistributedLock.Redis
1.0.0
dotnet add package GM.DistributedLock.Redis --version 1.0.0
NuGet\Install-Package GM.DistributedLock.Redis -Version 1.0.0
<PackageReference Include="GM.DistributedLock.Redis" Version="1.0.0" />
<PackageVersion Include="GM.DistributedLock.Redis" Version="1.0.0" />
<PackageReference Include="GM.DistributedLock.Redis" />
paket add GM.DistributedLock.Redis --version 1.0.0
#r "nuget: GM.DistributedLock.Redis, 1.0.0"
#:package GM.DistributedLock.Redis@1.0.0
#addin nuget:?package=GM.DistributedLock.Redis&version=1.0.0
#tool nuget:?package=GM.DistributedLock.Redis&version=1.0.0
<p align="center"> <img src="https://raw.githubusercontent.com/gmetskhvarishvili/GM.DistributedLock/master/icon.png" alt="GM.DistributedLock" width="140" height="140" /> </p>
GM.DistributedLock
A small, provider-agnostic distributed lock for .NET. Depend on one interface —
IDistributedLock — with TryAcquire (single shot) and Acquire (blocking with retry), each
returning an IAsyncDisposable handle that releases on dispose and is owner-safe (it never
releases a lock that expired and was re-acquired by someone else). Ships a single-process in-memory
implementation; add a real backend with GM.DistributedLock.Redis. Targets .NET 10.
Packages
The two packages version and release together (lockstep):
| Package | What it gives you |
|---|---|
GM.DistributedLock |
IDistributedLock, ILockHandle, and a single-process in-memory implementation (AddGMDistributedLock()) for dev and tests. |
GM.DistributedLock.Redis |
A real cross-process lock over StackExchange.Redis — SET NX PX to acquire, owner-checked Lua to release (AddGMRedisDistributedLock()). |
dotnet add package GM.DistributedLock # in-process
dotnet add package GM.DistributedLock.Redis # + Redis backend
Quick start
Register
using GM.DistributedLock; // in-process
builder.Services.AddGMDistributedLock();
// or, cross-process:
using GM.DistributedLock.Redis;
builder.Services.AddGMRedisDistributedLock(o => o.ConnectionString = "localhost:6379");
// or bind from configuration: AddGMRedisDistributedLock(builder.Configuration, "Redis");
Use it
Inject IDistributedLock — the same code works with either backend:
public class PayoutJob(IDistributedLock locks)
{
public async Task RunAsync(Guid accountId)
{
// Block up to 30s, retrying every 200ms, holding the lock for at most 60s.
await using var handle = await locks.AcquireAsync(
resource: $"payout:{accountId}",
expiry: TimeSpan.FromSeconds(60),
wait: TimeSpan.FromSeconds(30),
retryInterval: TimeSpan.FromMilliseconds(200));
// ... critical section: only one worker runs this per account ...
} // lock released here
}
Prefer a non-blocking attempt? Use TryAcquireAsync, which returns null when the lock is held:
await using var handle = await locks.TryAcquireAsync($"report:{id}", TimeSpan.FromMinutes(5));
if (handle is null) return; // someone else is already generating it
The interface
Task<ILockHandle?> TryAcquireAsync(string resource, TimeSpan expiry, CancellationToken ct = default);
Task<ILockHandle> AcquireAsync(string resource, TimeSpan expiry, TimeSpan wait, TimeSpan retryInterval, CancellationToken ct = default);
AcquireAsync throws LockAcquisitionException if it can't take the lock within wait. Every
lock has an expiry (TTL) so a crashed holder can't wedge the resource forever.
The Redis provider targets a single Redis endpoint (SET NX PX + owner-checked release), which is the right trade-off for the vast majority of apps. It is not a multi-node Redlock quorum.
Repository layout
GM.DistributedLock/ # IDistributedLock, ILockHandle, in-memory implementation
GM.DistributedLock.Redis/ # Redis implementation (StackExchange.Redis)
tests/GM.DistributedLock.Tests/ # xUnit tests for the in-memory lock
Building & testing
dotnet build -c Release
dotnet test -c Release
Releasing
Versioning is automated from Conventional Commits —
see CONTRIBUTING.md. Both packages share one version (Directory.Build.props)
and publish together to nuget.org on each release.
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- GM.DistributedLock (>= 1.0.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- StackExchange.Redis (>= 2.13.17)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 94 | 8/2/2026 |