17 using System.Threading;
27 private readonly
object _sync =
new object();
29 private long _available;
45 get { lock (_sync)
return _available; }
57 public LeakyBucket(
long capacity,
long refillAmount, TimeSpan refillInterval)
79 _available = capacity;
91 public void Consume(
long tokens,
long timeout = Timeout.Infinite)
93 if (timeout < Timeout.Infinite)
95 throw new ArgumentOutOfRangeException(nameof(timeout),
96 "Invalid timeout. Use -1 for no timeout, 0 for immediate timeout and a positive number " +
97 "of milliseconds to indicate a timeout. All other values are out of range."
101 var startTime = _timeProvider.GetUtcNow();
110 if (timeout != Timeout.Infinite)
113 var currentTime = _timeProvider.GetUtcNow();
114 var elapsedMilliseconds = (currentTime - startTime).TotalMilliseconds;
115 if (elapsedMilliseconds > timeout)
117 throw new TimeoutException(
"The operation timed out while waiting for the rate limit to be lifted.");
134 throw new ArgumentOutOfRangeException(nameof(tokens),
135 "Number of tokens to consume must be positive"
141 throw new ArgumentOutOfRangeException(nameof(tokens),
142 "Number of tokens to consume must be less than or equal to the capacity"
149 var refilled = Math.Max(0, _refill.Refill());
152 var deltaTokens = Math.Min(
Capacity - _available, refilled);
155 _available += deltaTokens;
157 if (tokens > _available)
160 Logging.Log.Trace($
"LeakyBucket.TryConsume({tokens}): Failed to consumed tokens. Available: {_available}");
165 _available = _available - tokens;
166 Logging.Log.Trace($
"LeakyBucket.TryConsume({tokens}): Successfully consumed tokens. Available: {_available}");