Files
natsdotnet/src/NATS.Server/JetStream/Publish/PublishPreconditions.cs
2026-02-23 12:11:19 -05:00

55 lines
1.6 KiB
C#

using System.Collections.Concurrent;
namespace NATS.Server.JetStream.Publish;
public sealed class PublishPreconditions
{
private readonly ConcurrentDictionary<string, DedupeEntry> _dedupe = new(StringComparer.Ordinal);
public bool IsDuplicate(string? msgId, int duplicateWindowMs, out ulong existingSequence)
{
existingSequence = 0;
if (string.IsNullOrEmpty(msgId))
return false;
if (!_dedupe.TryGetValue(msgId, out var entry))
return false;
if (duplicateWindowMs > 0
&& DateTime.UtcNow - entry.TimestampUtc > TimeSpan.FromMilliseconds(duplicateWindowMs))
{
_dedupe.TryRemove(msgId, out _);
return false;
}
existingSequence = entry.Sequence;
return true;
}
public void Record(string? msgId, ulong sequence)
{
if (string.IsNullOrEmpty(msgId))
return;
_dedupe[msgId] = new DedupeEntry(sequence, DateTime.UtcNow);
}
public void TrimOlderThan(int duplicateWindowMs)
{
if (duplicateWindowMs <= 0)
return;
var cutoff = DateTime.UtcNow.AddMilliseconds(-duplicateWindowMs);
foreach (var (key, entry) in _dedupe)
{
if (entry.TimestampUtc < cutoff)
_dedupe.TryRemove(key, out _);
}
}
public bool CheckExpectedLastSeq(ulong expectedLastSeq, ulong actualLastSeq)
=> expectedLastSeq == 0 || expectedLastSeq == actualLastSeq;
private readonly record struct DedupeEntry(ulong Sequence, DateTime TimestampUtc);
}