using System.Collections.Concurrent;
namespace NATS.Server;
///
/// Tracks slow consumer events per with optional threshold-based callbacks.
/// Go reference: server/client.go — handleSlowConsumer, markConnAsSlow.
///
public sealed class SlowConsumerTracker
{
private readonly ConcurrentDictionary _countsByKind = new();
private long _totalCount;
private readonly int _threshold;
private Action? _onThresholdExceeded;
///
/// When the total count reaches this value the registered callback is fired.
/// 0 means no threshold (callback never fires automatically).
///
public SlowConsumerTracker(int threshold = 0)
{
_threshold = threshold;
}
/// Total slow-consumer events recorded across all s.
public long TotalCount => Interlocked.Read(ref _totalCount);
///
/// Records one slow-consumer event for the given .
/// Increments both the per-kind counter and the total counter.
/// Fires the threshold callback if reaches the configured threshold.
///
public void RecordSlowConsumer(ClientKind kind)
{
_countsByKind.AddOrUpdate(kind, 1L, static (_, existing) => existing + 1L);
var total = Interlocked.Increment(ref _totalCount);
if (_threshold > 0 && total >= _threshold)
_onThresholdExceeded?.Invoke(kind);
}
/// Returns the number of slow-consumer events recorded for .
public long GetCount(ClientKind kind) =>
_countsByKind.TryGetValue(kind, out var count) ? count : 0L;
///
/// Registers a callback that is invoked (with the triggering )
/// each time the total count reaches or exceeds the configured threshold.
///
public void OnThresholdExceeded(Action callback) =>
_onThresholdExceeded = callback;
/// Resets all per-kind and total counters to zero.
public void Reset()
{
_countsByKind.Clear();
Interlocked.Exchange(ref _totalCount, 0L);
}
}