IdempotencyShield.Redis 1.0.2

dotnet add package IdempotencyShield.Redis --version 1.0.2
                    
NuGet\Install-Package IdempotencyShield.Redis -Version 1.0.2
                    
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="IdempotencyShield.Redis" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IdempotencyShield.Redis" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="IdempotencyShield.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 IdempotencyShield.Redis --version 1.0.2
                    
#r "nuget: IdempotencyShield.Redis, 1.0.2"
                    
#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 IdempotencyShield.Redis@1.0.2
                    
#: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=IdempotencyShield.Redis&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=IdempotencyShield.Redis&version=1.0.2
                    
Install as a Cake Tool

IdempotencyShield.Redis

Redis-backed implementation of IIdempotencyStore for the IdempotencyShield library. Enables distributed caching and locking for multi-instance ASP.NET Core deployments.

Installation

dotnet add package IdempotencyShield.Redis

Quick Start

Basic Setup

using IdempotencyShield.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add IdempotencyShield with Redis backend
builder.Services.AddIdempotencyShieldWithRedis("localhost:6379");

var app = builder.Build();

app.UseIdempotencyShield();
app.UseRouting();
app.MapControllers();

app.Run();

With Configuration

builder.Services.AddIdempotencyShieldWithRedis(
    redisConfiguration: "localhost:6379,password=mypassword,ssl=true",
    configureOptions: options =>
    {
        options.HeaderName = "X-Idempotency-Key";
        options.DefaultExpiryMinutes = 120;
        options.LockExpirationMilliseconds = 30000;  // Lock TTL
        options.LockWaitTimeoutMilliseconds = 5000;   // Spin-wait timeout
        options.FailureMode = IdempotencyFailureMode.FailSafe;
    });

Using ConfigurationOptions

using StackExchange.Redis;

var redisOptions = new ConfigurationOptions
{
    EndPoints = { "redis-master:6379", "redis-replica:6379" },
    Password = "your-password",
    Ssl = true,
    AbortOnConnectFail = false,
    ConnectRetry = 3,
    ConnectTimeout = 5000
};

builder.Services.AddIdempotencyShieldWithRedis(redisOptions);

Using Existing IConnectionMultiplexer

If you already have Redis configured in your application:

// Register Redis elsewhere
builder.Services.AddSingleton<IConnectionMultiplexer>(sp => 
{
    var configuration = ConfigurationOptions.Parse("localhost:6379");
    return ConnectionMultiplexer.Connect(configuration);
});

// Use existing connection
builder.Services.AddIdempotencyShieldWithRedis();

Redis Key Structure

The implementation uses the following key prefixes:

  • Cache Keys: idempotency:cache:{idempotency-key}

    • Stores serialized IdempotencyRecord (status, headers, body, hash)
    • Expires based on ExpiryInMinutes attribute parameter
  • Lock Keys: idempotency:lock:{idempotency-key}

    • Used for distributed locking via SET NX
    • TTL configured via LockExpirationMilliseconds (default: 30s)
    • Implements spin-wait with exponential backoff + jitter
    • Stores machine name for debugging

Features

Distributed Locking - Uses Redis SET NX for atomic lock acquisition
Spin-Wait with Jitter - Retries lock acquisition with randomized delays to avoid thundering herd
Automatic Expiration - TTL on both cache and locks
JSON Serialization - Efficient storage using System.Text.Json
Error Handling - Gracefully handles corrupted data
Deadlock Prevention - Locks auto-expire based on configuration
Multi-Instance Safe - Designed for load-balanced deployments

Lock Mechanism

The Redis store implements a sophisticated spin-wait locking mechanism:

  1. Atomic Lock Acquisition: Uses SET NX EX for atomic lock creation with TTL
  2. Spin-Wait Strategy: If lock is held, retries with exponential backoff (15-50ms with jitter)
  3. Configurable Timeout: Respects LockWaitTimeoutMilliseconds for maximum wait time
  4. Automatic Expiration: Lock TTL prevents stuck locks from crashed processes

Configuration Options

Redis Connection String Format

server:port[,server:port][,options]

Common Options:

  • password=xxx - Redis password
  • ssl=true - Enable SSL/TLS
  • abortConnect=false - Don't fail on initial connection error
  • connectRetry=3 - Number of retry attempts
  • connectTimeout=5000 - Connection timeout in milliseconds
  • syncTimeout=1000 - Operation timeout in milliseconds

Example:

redis.example.com:6379,password=secret,ssl=true,abortConnect=false

Production Recommendations

1. Connection Resilience

var redisOptions = new ConfigurationOptions
{
    EndPoints = { "redis-primary:6379" },
    AbortOnConnectFail = false, // Don't crash if Redis is down
    ConnectRetry = 3,
    ReconnectRetryPolicy = new ExponentialRetry(5000),
    KeepAlive = 60
};

2. Redis Cluster Setup

For high availability, use Redis Cluster or Sentinel:

var redisOptions = new ConfigurationOptions
{
    EndPoints = 
    { 
        "redis-node1:6379",
        "redis-node2:6379", 
        "redis-node3:6379"
    },
    Password = "your-password",
    Ssl = true
};

3. Monitoring

Monitor Redis key usage:

# Count idempotency keys
redis-cli --scan --pattern "idempotency:*" | wc -l

# Check lock keys (should be minimal)
redis-cli --scan --pattern "idempotency:lock:*"

# View a cached record
redis-cli GET "idempotency:cache:your-key-here"

4. Memory Management

Set Redis maxmemory-policy to allkeys-lru or volatile-ttl:

# redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru

Comparison with InMemoryStore

Feature InMemoryStore RedisStore
Use Case Single instance, dev/test Multi-instance production
Distributed ❌ No ✅ Yes
Persistence ❌ Lost on restart ✅ Persisted (if configured)
Scalability Single server Horizontal scaling
Lock Safety Process-local Distributed
Setup Complexity None Requires Redis

Thread Safety

The RedisIdempotencyStore is fully thread-safe:

  • Redis operations are atomic
  • SET NX provides distributed lock guarantees
  • JSON serialization is thread-safe
  • No shared mutable state

Performance Considerations

  • Network Latency: ~1-2ms per Redis operation (local network)
  • Serialization Overhead: ~0.5ms per JSON operation
  • Lock Contention: Non-blocking, immediate 409 response
  • Cache Hits: Near-instant (single Redis GET)

Troubleshooting

Connection Failures

// Add logging to diagnose connection issues
var redisOptions = ConfigurationOptions.Parse("localhost:6379");
redisOptions.AbortOnConnectFail = false;

var redis = ConnectionMultiplexer.Connect(redisOptions);
redis.ConnectionFailed += (sender, args) =>
{
    Console.WriteLine($"Redis connection failed: {args.Exception}");
};

services.AddSingleton(redis);

Lock Key Leaks

If lock keys accumulate, increase cleanup:

# Manual cleanup (use with caution)
redis-cli --scan --pattern "idempotency:lock:*" | xargs redis-cli DEL

Lock keys should auto-expire after 30 seconds. Persistent lock keys indicate crashed processes.

License

MIT License - See LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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 is compatible.  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 was computed.  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
1.0.2 484 12/11/2025
1.0.1 459 12/10/2025
1.0.0 472 12/10/2025