IdempotencyShield.Redis
1.0.2
dotnet add package IdempotencyShield.Redis --version 1.0.2
NuGet\Install-Package IdempotencyShield.Redis -Version 1.0.2
<PackageReference Include="IdempotencyShield.Redis" Version="1.0.2" />
<PackageVersion Include="IdempotencyShield.Redis" Version="1.0.2" />
<PackageReference Include="IdempotencyShield.Redis" />
paket add IdempotencyShield.Redis --version 1.0.2
#r "nuget: IdempotencyShield.Redis, 1.0.2"
#:package IdempotencyShield.Redis@1.0.2
#addin nuget:?package=IdempotencyShield.Redis&version=1.0.2
#tool nuget:?package=IdempotencyShield.Redis&version=1.0.2
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
ExpiryInMinutesattribute parameter
- Stores serialized
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
- Used for distributed locking via
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:
- Atomic Lock Acquisition: Uses
SET NX EXfor atomic lock creation with TTL - Spin-Wait Strategy: If lock is held, retries with exponential backoff (15-50ms with jitter)
- Configurable Timeout: Respects
LockWaitTimeoutMillisecondsfor maximum wait time - 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 passwordssl=true- Enable SSL/TLSabortConnect=false- Don't fail on initial connection errorconnectRetry=3- Number of retry attemptsconnectTimeout=5000- Connection timeout in millisecondssyncTimeout=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 NXprovides 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.
Related Packages
- IdempotencyShield: Core library.
- IdempotencyShield.EntityFrameworkCore: Alternative storage using Entity Framework Core.
License
MIT License - See LICENSE file for details.
| Product | Versions 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. |
-
net6.0
- IdempotencyShield (>= 1.0.2)
- StackExchange.Redis (>= 2.8.16)
- System.Text.Json (>= 8.0.5)
-
net8.0
- IdempotencyShield (>= 1.0.2)
- StackExchange.Redis (>= 2.8.16)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.