/// <summary> /// Blocks until the specified number of tokens are available for consumption /// and then consumes that number of tokens. /// </summary> /// <param name="tokens">The number of tokens to consume</param> /// <param name="timeout">The maximum amount of time, in milliseconds, to block. An exception is /// throw in the event it takes longer than the stated timeout to consume the requested number /// of tokens</param> public void Consume(long tokens, long timeout = Timeout.Infinite) { if (timeout < Timeout.Infinite) { throw new ArgumentOutOfRangeException(nameof(timeout), "Invalid timeout. Use -1 for no timeout, 0 for immediate timeout and a positive number " + "of milliseconds to indicate a timeout. All other values are out of range." ); } var startTime = _timeProvider.GetUtcNow(); while (true) { if (TryConsume(tokens)) { break; } if (timeout != Timeout.Infinite) { // determine if the requested timeout has elapsed var currentTime = _timeProvider.GetUtcNow(); var elapsedMilliseconds = (currentTime - startTime).TotalMilliseconds; if (elapsedMilliseconds > timeout) { throw new TimeoutException("The operation timed out while waiting for the rate limit to be lifted."); } } _sleep.Sleep(); } }
/// <summary> /// Consumes multiple tokens from the bucket. If enough tokens are not currently available then this method will block /// </summary> /// <param name="numTokens">The number of tokens to consume from the bucket, must be a positive number.</param> public void Consume(long numTokens) { while (true) { if (TryConsume(numTokens)) { break; } _sleepStrategy.Sleep(); } }
/// <summary> /// Consume multiple tokens from the bucket asynchronously. This method does not block /// <param name="numTokens">The number of tokens to consume from the bucket, must be a positive number.</param> /// <returns>A task that returns once the requested tokens have been consumed</returns> /// </summary> public async Task Consume(long numTokens, CancellationToken cancellationToken = default(CancellationToken)) { while (true) { if (await TryConsume(numTokens).ConfigureAwait(false)) { break; } await _sleepStrategy.Sleep(cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); } }