Soenneker.Deduplication.Redis
11.0.177
Prefix Reserved
dotnet add package Soenneker.Deduplication.Redis --version 11.0.177
NuGet\Install-Package Soenneker.Deduplication.Redis -Version 11.0.177
<PackageReference Include="Soenneker.Deduplication.Redis" Version="11.0.177" />
<PackageVersion Include="Soenneker.Deduplication.Redis" Version="11.0.177" />
<PackageReference Include="Soenneker.Deduplication.Redis" />
paket add Soenneker.Deduplication.Redis --version 11.0.177
#r "nuget: Soenneker.Deduplication.Redis, 11.0.177"
#:package Soenneker.Deduplication.Redis@11.0.177
#addin nuget:?package=Soenneker.Deduplication.Redis&version=11.0.177
#tool nuget:?package=Soenneker.Deduplication.Redis&version=11.0.177
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 | net11.0 is compatible. |
-
net11.0
- Soenneker.Hashing.XxHash (>= 11.0.135)
- Soenneker.Redis.Client (>= 11.0.2398)
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 |
|---|---|---|
| 11.0.177 | 45 | 11/12/2026 |
| 11.0.176 | 57 | 11/11/2026 |
| 11.0.175 | 52 | 11/11/2026 |
| 11.0.174 | 48 | 11/11/2026 |
| 11.0.173 | 44 | 11/11/2026 |
| 11.0.172 | 47 | 11/11/2026 |
| 11.0.171 | 59 | 11/11/2026 |
| 11.0.170 | 64 | 11/11/2026 |
| 11.0.169 | 66 | 11/11/2026 |
| 11.0.168 | 94 | 11/3/2026 |
| 11.0.167 | 90 | 11/3/2026 |
| 11.0.166 | 93 | 11/3/2026 |
| 11.0.165 | 91 | 11/3/2026 |
| 11.0.164 | 98 | 11/2/2026 |
| 11.0.163 | 103 | 10/30/2026 |
| 11.0.162 | 103 | 10/27/2026 |
| 11.0.161 | 95 | 10/27/2026 |
| 11.0.160 | 99 | 10/26/2026 |
| 11.0.155 | 93 | 10/26/2026 |
| 11.0.154 | 92 | 10/26/2026 |
Updated Soenneker.Redis.Client to 11.0.2398