Rystem.Concurrency.Redis 10.0.7

There is a newer version of this package available.
See the version list below for details.
dotnet add package Rystem.Concurrency.Redis --version 10.0.7
                    
NuGet\Install-Package Rystem.Concurrency.Redis -Version 10.0.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Rystem.Concurrency.Redis" Version="10.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rystem.Concurrency.Redis" Version="10.0.7" />
                    
Directory.Packages.props
<PackageReference Include="Rystem.Concurrency.Redis" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Rystem.Concurrency.Redis --version 10.0.7
                    
#r "nuget: Rystem.Concurrency.Redis, 10.0.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Rystem.Concurrency.Redis@10.0.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Rystem.Concurrency.Redis&version=10.0.7
                    
Install as a Cake Addin
#tool nuget:?package=Rystem.Concurrency.Redis&version=10.0.7
                    
Install as a Cake Tool

What is Rystem?

Rystem.Concurrency.Redis

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:

  • multiple application instances
  • multiple worker processes
  • multiple machines or containers

The package keeps the same higher-level APIs from Rystem.Concurrency:

  • ILock
  • IRaceCodition
  • ILockable

Only the storage backend changes.

Resources

Installation

dotnet add package Rystem.Concurrency.Redis

The current 10.x package targets net10.0 and builds on top of:

Package Architecture

The 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.

Table of Contents


Distributed Async Lock

Register a distributed ILock with Redis as the backing store:

services.AddRedisLock(options =>
{
    options.ConnectionString = configuration["ConnectionString:Redis"]!;
});

Internally this does two things:

  • registers the standard ILock executor
  • registers RedisLock as the active ILockable

Usage 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.


Distributed Race Condition

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.


Redis Lockable Only

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.


Redis Backend Behavior

RedisLock implements ILockable like this:

  • AcquireAsync(key, maxWindow) uses StringSetAsync(..., When.NotExists)
  • IsAcquiredAsync(key) checks whether the key currently exists
  • ReleaseAsync(key) uses a Lua script so the key is deleted only when the stored value matches the expected key value

That gives you two useful properties:

  • acquisition is atomic across all Redis-connected processes
  • release is guarded, so one caller does not accidentally delete another caller's lock entry

The optional maxWindow parameter is important for race-condition scenarios because it becomes the Redis key expiration window.


Configuration and Registration Notes

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 registration

That 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.


Repository Examples

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
10.0.8 100 5/13/2026
10.0.7 114 3/26/2026
10.0.6 424,339 3/3/2026
10.0.5 116 2/22/2026
10.0.4 121 2/9/2026
10.0.3 147,884 1/28/2026
10.0.1 209,344 11/12/2025
9.1.3 233 9/2/2025
9.1.2 764,764 5/29/2025
9.1.1 97,856 5/2/2025
9.0.32 186,688 4/15/2025
9.0.31 5,763 4/2/2025
9.0.30 88,763 3/26/2025
9.0.29 8,984 3/18/2025
9.0.28 225 3/17/2025
9.0.27 205 3/16/2025
9.0.26 199 3/13/2025
9.0.25 52,079 3/9/2025
9.0.21 692 3/6/2025
9.0.20 19,567 3/6/2025
Loading failed