Soenneker.Deduplication.Redis
4.0.100
Prefix Reserved
See the version list below for details.
dotnet add package Soenneker.Deduplication.Redis --version 4.0.100
NuGet\Install-Package Soenneker.Deduplication.Redis -Version 4.0.100
<PackageReference Include="Soenneker.Deduplication.Redis" Version="4.0.100" />
<PackageVersion Include="Soenneker.Deduplication.Redis" Version="4.0.100" />
<PackageReference Include="Soenneker.Deduplication.Redis" />
paket add Soenneker.Deduplication.Redis --version 4.0.100
#r "nuget: Soenneker.Deduplication.Redis, 4.0.100"
#:package Soenneker.Deduplication.Redis@4.0.100
#addin nuget:?package=Soenneker.Deduplication.Redis&version=4.0.100
#tool nuget:?package=Soenneker.Deduplication.Redis&version=4.0.100
Soenneker.Deduplication.Redis
Distributed, time-bounded duplicate suppression using atomic Redis markers.
Installation
dotnet add package Soenneker.Deduplication.Redis
Registration
using Soenneker.Deduplication.Redis.Registrars;
services.AddRedisDedupeAsSingleton();
This also registers Soenneker.Redis.Client; configure its Redis connection using that package’s normal configuration.
Usage
using Soenneker.Deduplication.Redis.Abstract;
public sealed class WebhookConsumer(IRedisDedupe dedupe)
{
public async ValueTask Handle(string eventId, CancellationToken cancellationToken)
{
bool firstDelivery = await dedupe.TryMarkSeen(
cacheKey: "dedupe:webhooks:stripe",
cacheValue: eventId,
expiration: TimeSpan.FromHours(24),
cancellationToken);
if (!firstDelivery)
return;
await ProcessWebhook(cancellationToken);
}
}
TryMarkSeen uses Redis SET ... NX with the TTL in the same command. Concurrent callers across processes get one true result while the marker exists; later callers get false. Redis connection and command failures propagate instead of being reported as duplicates.
Lookup and removal
bool seen = await dedupe.Contains("dedupe:webhooks:stripe", eventId, cancellationToken);
bool removed = await dedupe.TryRemove("dedupe:webhooks:stripe", eventId, cancellationToken);
Contains does not refresh the TTL. TryRemove performs one atomic Redis delete and returns whether a marker was deleted.
String and ReadOnlySpan<char> overloads hash UTF-16 characters. TryMarkSeenUtf8, ContainsUtf8, and TryRemoveUtf8 hash the supplied bytes. Use the same representation for every operation on a value; the UTF-16 string "abc" and its UTF-8 bytes are different dedupe keys.
Redis keys and retention
The stored key is:
{cacheKey}:{lowercase 16-character XXH3-64 hash}
Only the 64-bit hash marker is stored as the value, but cacheKey remains visible in Redis. Choose a stable, non-secret namespace. Different inputs can theoretically collide, so use a full-key design when collision tolerance is unacceptable.
Always set an expiration for open-ended inputs unless permanent markers and their storage growth are intentional. A non-positive expiration is rejected; null creates a marker without automatic expiry.
Delivery semantics
This package is a duplicate-suppression primitive, not an exactly-once transaction. The marker and your business operation are separate: a process can fail after claiming a value but before completing the work. For durable message processing, combine it with an inbox/outbox or another transactional idempotency design. Redis eviction, data loss, manual deletion, or TTL expiry can also make a value eligible again.
| 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
- Soenneker.Hashing.XxHash (>= 4.0.92)
- Soenneker.Redis.Client (>= 4.0.2325)
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 |
|---|---|---|
| 4.0.116 | 0 | 9/19/2026 |
| 4.0.115 | 42 | 9/17/2026 |
| 4.0.114 | 47 | 9/17/2026 |
| 4.0.113 | 44 | 9/16/2026 |
| 4.0.112 | 39 | 9/16/2026 |
| 4.0.111 | 37 | 9/16/2026 |
| 4.0.110 | 44 | 9/16/2026 |
| 4.0.109 | 62 | 9/15/2026 |
| 4.0.108 | 63 | 9/15/2026 |
| 4.0.107 | 79 | 9/13/2026 |
| 4.0.106 | 87 | 9/13/2026 |
| 4.0.105 | 91 | 9/13/2026 |
| 4.0.103 | 86 | 9/13/2026 |
| 4.0.102 | 85 | 9/13/2026 |
| 4.0.101 | 85 | 9/12/2026 |
| 4.0.100 | 86 | 9/12/2026 |
| 4.0.99 | 84 | 9/11/2026 |
| 4.0.98 | 91 | 9/9/2026 |
| 4.0.97 | 92 | 9/9/2026 |
| 4.0.96 | 85 | 9/9/2026 |