SpecialBusinessRateLimiter.cs 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. using System.Collections.Concurrent;
  2. namespace molilian.core
  3. {
  4. public static class SpecialBusinessRateLimiter
  5. {
  6. private static readonly ConcurrentDictionary<string, SlidingWindowState> States = new();
  7. public static bool TryAcquire(string bucketKey, int limit, TimeSpan window)
  8. {
  9. if (string.IsNullOrWhiteSpace(bucketKey)) return true;
  10. if (limit <= 0 || window <= TimeSpan.Zero) return true;
  11. var state = States.GetOrAdd(bucketKey, _ => new SlidingWindowState());
  12. var nowTicks = DateTime.UtcNow.Ticks;
  13. var minTicks = nowTicks - window.Ticks;
  14. lock (state.SyncRoot)
  15. {
  16. while (state.Timestamps.Count > 0 && state.Timestamps.Peek() < minTicks)
  17. {
  18. state.Timestamps.Dequeue();
  19. }
  20. if (state.Timestamps.Count >= limit)
  21. {
  22. return false;
  23. }
  24. state.Timestamps.Enqueue(nowTicks);
  25. return true;
  26. }
  27. }
  28. private sealed class SlidingWindowState
  29. {
  30. public object SyncRoot { get; } = new();
  31. public Queue<long> Timestamps { get; } = new();
  32. }
  33. }
  34. }