![]() |
VOOZH | about |
dotnet add package Rystem.Concurrency.Redis --version 10.0.8
NuGet\Install-Package Rystem.Concurrency.Redis -Version 10.0.8
<PackageReference Include="Rystem.Concurrency.Redis" Version="10.0.8" />
<PackageVersion Include="Rystem.Concurrency.Redis" Version="10.0.8" />Directory.Packages.props
<PackageReference Include="Rystem.Concurrency.Redis" />Project file
paket add Rystem.Concurrency.Redis --version 10.0.8
#r "nuget: Rystem.Concurrency.Redis, 10.0.8"
#:package Rystem.Concurrency.Redis@10.0.8
#addin nuget:?package=Rystem.Concurrency.Redis&version=10.0.8Install as a Cake Addin
#tool nuget:?package=Rystem.Concurrency.Redis&version=10.0.8Install as a Cake Tool
Rystem.Concurrency.Redis swaps the default in-memory ILockable from Rystem.Concurrency with a Redis-backed distributed implementation.
Use it when lock and race-condition state must be shared across:
The package keeps the same higher-level APIs from Rystem.Concurrency:
ILockIRaceCoditionILockableOnly the storage backend changes.
dotnet add package Rystem.Concurrency.Redis
The current 10.x package targets net10.0 and builds on top of:
StackExchange.RedisRystem.ConcurrencyThe package is intentionally small and only adds the Redis-specific pieces.
| Piece | Purpose |
|---|---|
RedisConfiguration |
Holds the Redis connection string |
RedisLock |
Implements ILockable on top of StackExchange.Redis |
AddRedisLock(...) |
Registers ILock plus the Redis lockable |
AddRaceConditionWithRedis(...) |
Registers IRaceCodition plus the Redis lock stack |
AddRedisLockable(...) |
Registers only the Redis ILockable backend |
Conceptually, this package does not replace the concurrency model. It only replaces the backend used by that model.
Register a distributed ILock with Redis as the backing store:
services.AddRedisLock(options =>
{
options.ConnectionString = configuration["ConnectionString:Redis"]!;
});
Internally this does two things:
ILock executorRedisLock as the active ILockableUsage stays identical to the in-memory version from Rystem.Concurrency:
using System.Threading.Concurrent;
LockResponse response = await distributedLock.ExecuteAsync(
async () =>
{
await Task.Delay(15);
await SaveAsync();
},
key: "inventory");
if (response.InException)
throw response.Exceptions!;
The repository test in src/Extensions/Concurrency/Test/Rystem.Concurrency.UnitTest/RedisLockTest.cs uses this registration and starts 100 concurrent lock executions. The final counter still ends at 200, confirming that the distributed backend preserves the same serialized behavior as the in-memory version.
Register the race-condition guard with Redis:
services.AddRaceConditionWithRedis(options =>
{
options.ConnectionString = configuration["ConnectionString:Redis"]!;
});
This composes:
AddRedisLock(...)AddRaceConditionExecutor()So the high-level race-condition logic remains the same as the base package, but the lock state is now shared through Redis.
Usage also stays the same:
using System.Threading.Concurrent;
RaceConditionResponse response = await raceCondition.ExecuteAsync(
async () =>
{
await Task.Delay(15);
await RefreshCacheAsync();
},
key: "cache-refresh",
timeWindow: TimeSpan.FromSeconds(30));
if (response.IsExecuted)
{
// this instance won and executed the action
}
There is no separate Redis-specific race-condition test in the repository at the moment, so this section is source-backed rather than test-backed. The important implementation detail is that the Redis package reuses the same RaceConditionExecutor from the base concurrency package.
If you want Redis as the backend but your own higher-level executor, register only ILockable:
services.AddRedisLockable(options =>
{
options.ConnectionString = configuration["ConnectionString:Redis"]!;
});
Then add your own executor on top:
services.AddLockExecutor<MyCustomLock>();
services.AddRaceConditionExecutor<MyCustomRaceCondition>();
This is the lowest-level integration point exposed by the package.
RedisLock implements ILockable like this:
AcquireAsync(key, maxWindow) uses StringSetAsync(..., When.NotExists)IsAcquiredAsync(key) checks whether the key currently existsReleaseAsync(key) uses a Lua script so the key is deleted only when the stored value matches the expected key valueThat gives you two useful properties:
The optional maxWindow parameter is important for race-condition scenarios because it becomes the Redis key expiration window.
RedisConfiguration is intentionally minimal:
public sealed class RedisConfiguration
{
public string? ConnectionString { get; set; }
}
The package creates the IConnectionMultiplexer immediately during registration:
services.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect(redisConfiguration.ConnectionString));
So connection issues can surface as soon as the service collection is being built.
Also note the registration order behavior:
AddRedisLockable(...) uses TryAddSingleton<ILockable, RedisLock>()AddRedisLock(...) and AddRaceConditionWithRedis(...) rely on that registrationThat means if another ILockable has already been registered earlier, Redis will not override it automatically. In practice, use the Redis registration path as the primary setup for the service collection instead of mixing it with AddLock() or AddRaceCondition() first.
The most useful references for this package are:
This README stays focused because Rystem.Concurrency.Redis is a backend package, not a separate concurrency model. The API shape comes from Rystem.Concurrency; Redis only supplies the shared lock state.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.8 | 5,532 | 5/13/2026 |
| 10.0.7 | 125 | 3/26/2026 |
| 10.0.6 | 433,508 | 3/3/2026 |
| 10.0.5 | 122 | 2/22/2026 |
| 10.0.4 | 125 | 2/9/2026 |
| 10.0.3 | 147,892 | 1/28/2026 |
| 10.0.1 | 209,350 | 11/12/2025 |
| 9.1.3 | 244 | 9/2/2025 |
| 9.1.2 | 764,768 | 5/29/2025 |
| 9.1.1 | 97,860 | 5/2/2025 |
| 9.0.32 | 186,693 | 4/15/2025 |
| 9.0.31 | 5,768 | 4/2/2025 |
| 9.0.30 | 88,768 | 3/26/2025 |
| 9.0.29 | 8,989 | 3/18/2025 |
| 9.0.28 | 231 | 3/17/2025 |
| 9.0.27 | 210 | 3/16/2025 |
| 9.0.26 | 204 | 3/13/2025 |
| 9.0.25 | 52,083 | 3/9/2025 |
| 9.0.21 | 696 | 3/6/2025 |
| 9.0.20 | 19,572 | 3/6/2025 |