chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a CPU intensive means of waiting for more tokens to be available in <see cref="ITokenBucket"/>.
|
||||
/// This strategy is only viable when the requested number of tokens is expected to become available in an
|
||||
/// extremely short period of time. This implementation aims to keep the current thread executing to prevent
|
||||
/// potential content switches arising from a thread yielding or sleeping strategy.
|
||||
/// </summary>
|
||||
public class BusyWaitSleepStrategy : ISleepStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a CPU intensive sleep by executing <see cref="Thread.SpinWait"/> for a single spin.
|
||||
/// </summary>
|
||||
public void Sleep()
|
||||
{
|
||||
Thread.SpinWait(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a refill strategy that has a constant, quantized refill rate.
|
||||
/// For example, after 1 minute passes add 5 units. If 59 seconds has passed, it will add zero unit,
|
||||
/// but if 2 minutes have passed, then 10 units would be added.
|
||||
/// </summary>
|
||||
public class FixedIntervalRefillStrategy : IRefillStrategy
|
||||
{
|
||||
private readonly object _sync = new object();
|
||||
|
||||
private long _nextRefillTimeTicks;
|
||||
|
||||
private readonly long _refillAmount;
|
||||
private readonly long _refillIntervalTicks;
|
||||
private readonly ITimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FixedIntervalRefillStrategy"/> class.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Provides the current time used for determining how much time has elapsed
|
||||
/// between invocations of the refill method</param>
|
||||
/// <param name="refillAmount">Defines the constant number of tokens to be made available for consumption
|
||||
/// each time the provided <paramref name="refillInterval"/> has passed</param>
|
||||
/// <param name="refillInterval">The amount of time that must pass before adding the specified <paramref name="refillAmount"/>
|
||||
/// back to the bucket</param>
|
||||
public FixedIntervalRefillStrategy(ITimeProvider timeProvider, long refillAmount, TimeSpan refillInterval)
|
||||
{
|
||||
_timeProvider = timeProvider;
|
||||
_refillAmount = refillAmount;
|
||||
_refillIntervalTicks = refillInterval.Ticks;
|
||||
_nextRefillTimeTicks = _timeProvider.GetUtcNow().Ticks + _refillIntervalTicks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the number of new tokens made available to the bucket for consumption by determining the
|
||||
/// number of time intervals that have passed and multiplying by the number of tokens to refill for
|
||||
/// each time interval.
|
||||
/// </summary>
|
||||
public long Refill()
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
var currentTimeTicks = _timeProvider.GetUtcNow().Ticks;
|
||||
if (currentTimeTicks < _nextRefillTimeTicks)
|
||||
{
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// determine number of time increments that have passed
|
||||
var deltaTimeTicks = currentTimeTicks - _nextRefillTimeTicks;
|
||||
var intervalsElapsed = 1 + Math.Max(deltaTimeTicks / _refillIntervalTicks, 0);
|
||||
|
||||
// update next refill time as quantized via the number of passed intervals
|
||||
_nextRefillTimeTicks += _refillIntervalTicks * intervalsElapsed;
|
||||
|
||||
// refill by the tokens per interval times the number of intervals elapsed
|
||||
return _refillAmount * intervalsElapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a strategy for making tokens available for consumption in the <see cref="ITokenBucket"/>
|
||||
/// </summary>
|
||||
public interface IRefillStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the number of new tokens made available, typically via the passing of time.
|
||||
/// </summary>
|
||||
long Refill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a strategy for sleeping the current thread of execution. This is currently used via the
|
||||
/// <see cref="ITokenBucket.Consume"/> in order to wait for new tokens to become available for consumption.
|
||||
/// </summary>
|
||||
public interface ISleepStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Sleeps the current thread in an implementation specific way
|
||||
/// and for an implementation specific amount of time
|
||||
/// </summary>
|
||||
void Sleep();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a token bucket for rate limiting
|
||||
/// See: https://en.wikipedia.org/wiki/Token_bucket
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This code is ported from https://github.com/mxplusb/TokenBucket - since it's a dotnet core
|
||||
/// project, there were issued importing the nuget package directly. The referenced repository
|
||||
/// is provided under the Apache V2 license.
|
||||
/// </remarks>
|
||||
public interface ITokenBucket
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the maximum capacity of tokens this bucket can hold.
|
||||
/// </summary>
|
||||
long Capacity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of currently available tokens for consumption
|
||||
/// </summary>
|
||||
long AvailableTokens { get; }
|
||||
|
||||
/// <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. A <see cref="TimeoutException"/>
|
||||
/// is throw in the event it takes longer than the stated timeout to consume the requested number of tokens.
|
||||
/// The default timeout is set to infinite, which will block forever.</param>
|
||||
void Consume(long tokens, long timeout = Timeout.Infinite);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to consume the specified number of tokens from the bucket. If the
|
||||
/// requested number of tokens are not immediately available, then this method
|
||||
/// will return false to indicate that zero tokens have been consumed.
|
||||
/// </summary>
|
||||
bool TryConsume(long tokens);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ITokenBucket"/> that implements the leaky bucket algorithm
|
||||
/// See: https://en.wikipedia.org/wiki/Leaky_bucket
|
||||
/// </summary>
|
||||
public class LeakyBucket : ITokenBucket
|
||||
{
|
||||
private readonly object _sync = new object();
|
||||
|
||||
private long _available;
|
||||
private readonly ISleepStrategy _sleep;
|
||||
private readonly IRefillStrategy _refill;
|
||||
private readonly ITimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum capacity of tokens this bucket can hold.
|
||||
/// </summary>
|
||||
public long Capacity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of currently available tokens for consumption
|
||||
/// </summary>
|
||||
public long AvailableTokens
|
||||
{
|
||||
// synchronized read w/ the modification of available tokens in TryConsume
|
||||
get { lock (_sync) return _available; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LeakyBucket"/> class.
|
||||
/// This constructor initializes the bucket using the <see cref="ThreadSleepStrategy.Sleep"/> with a 1 millisecond
|
||||
/// sleep to prevent being CPU intensive and uses the <see cref="FixedIntervalRefillStrategy"/> to refill bucket
|
||||
/// tokens according to the <paramref name="refillAmount"/> and <paramref name="refillInterval"/> parameters.
|
||||
/// </summary>
|
||||
/// <param name="capacity">The maximum number of tokens this bucket can hold</param>
|
||||
/// <param name="refillAmount">The number of tokens to add to the bucket each <paramref name="refillInterval"/></param>
|
||||
/// <param name="refillInterval">The interval which after passing more tokens are added to the bucket</param>
|
||||
public LeakyBucket(long capacity, long refillAmount, TimeSpan refillInterval)
|
||||
: this(capacity, ThreadSleepStrategy.Sleeping(1),
|
||||
new FixedIntervalRefillStrategy(RealTimeProvider.Instance, refillAmount, refillInterval)
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LeakyBucket"/> class
|
||||
/// </summary>
|
||||
/// <param name="capacity">The maximum number of tokens this bucket can hold</param>
|
||||
/// <param name="sleep">Defines the <see cref="ISleepStrategy"/> used when <see cref="Consume"/> is invoked
|
||||
/// but the bucket does not have enough tokens yet</param>
|
||||
/// <param name="refill">Defines the <see cref="IRefillStrategy"/> that computes how many tokens to add
|
||||
/// back to the bucket each time consumption is attempted</param>
|
||||
/// <param name="timeProvider">Defines the <see cref="ITimeProvider"/> used to enforce timeouts when
|
||||
/// invoking <see cref="Consume"/></param>
|
||||
public LeakyBucket(long capacity, ISleepStrategy sleep, IRefillStrategy refill, ITimeProvider timeProvider = null)
|
||||
{
|
||||
_sleep = sleep;
|
||||
_refill = refill;
|
||||
Capacity = capacity;
|
||||
_available = capacity;
|
||||
_timeProvider = timeProvider ?? RealTimeProvider.Instance;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Attempts to consume the specified number of tokens from the bucket. If the
|
||||
/// requested number of tokens are not immediately available, then this method
|
||||
/// will return false to indicate that zero tokens have been consumed.
|
||||
/// </summary>
|
||||
public bool TryConsume(long tokens)
|
||||
{
|
||||
if (tokens <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(tokens),
|
||||
"Number of tokens to consume must be positive"
|
||||
);
|
||||
}
|
||||
|
||||
if (tokens > Capacity)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(tokens),
|
||||
"Number of tokens to consume must be less than or equal to the capacity"
|
||||
);
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
// determine how many units have become available since last invocation
|
||||
var refilled = Math.Max(0, _refill.Refill());
|
||||
|
||||
// the number of tokens to add, the max of which is the difference between capacity and currently available
|
||||
var deltaTokens = Math.Min(Capacity - _available, refilled);
|
||||
|
||||
// update the available number of units with the new tokens
|
||||
_available += deltaTokens;
|
||||
|
||||
if (tokens > _available)
|
||||
{
|
||||
// we don't have enough tokens yet
|
||||
Logging.Log.Trace($"LeakyBucket.TryConsume({tokens}): Failed to consumed tokens. Available: {_available}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// subtract the number of tokens consumed
|
||||
_available = _available - tokens;
|
||||
Logging.Log.Trace($"LeakyBucket.TryConsume({tokens}): Successfully consumed tokens. Available: {_available}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a CPU non-intensive means of waiting for more tokens to be available in <see cref="ITokenBucket"/>.
|
||||
/// This strategy should be the most commonly used as it either sleeps or yields the currently executing thread,
|
||||
/// allowing for other threads to execute while the current thread is blocked and waiting for new tokens to become
|
||||
/// available in the bucket for consumption.
|
||||
/// </summary>
|
||||
public class ThreadSleepStrategy : ISleepStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an instance of <see cref="ISleepStrategy"/> that yields the current thread
|
||||
/// </summary>
|
||||
public static readonly ISleepStrategy Yielding = new ThreadSleepStrategy(0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of <see cref="ISleepStrategy"/> that sleeps the current thread for
|
||||
/// the specified number of milliseconds
|
||||
/// </summary>
|
||||
/// <param name="milliseconds">The duration of time to sleep, in milliseconds</param>
|
||||
public static ISleepStrategy Sleeping(int milliseconds) => new ThreadSleepStrategy(milliseconds);
|
||||
|
||||
private readonly int _milliseconds;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ThreadSleepStrategy"/> using the specified
|
||||
/// number of <paramref name="milliseconds"/> for each <see cref="Sleep"/> invocation.
|
||||
/// </summary>
|
||||
/// <param name="milliseconds">The duration of time to sleep, in milliseconds</param>
|
||||
public ThreadSleepStrategy(int milliseconds)
|
||||
{
|
||||
_milliseconds = milliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sleeps the current thread using the initialized number of milliseconds
|
||||
/// </summary>
|
||||
public void Sleep()
|
||||
{
|
||||
Thread.Sleep(_milliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Util.RateLimit
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for interacting with <see cref="ITokenBucket"/> instances as well
|
||||
/// as access to the <see cref="NullTokenBucket"/> via <see cref="TokenBucket.Null"/>
|
||||
/// </summary>
|
||||
public static class TokenBucket
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an <see cref="ITokenBucket"/> that always permits consumption
|
||||
/// </summary>
|
||||
public static ITokenBucket Null = new NullTokenBucket();
|
||||
|
||||
/// <summary>
|
||||
/// Provides an overload of <see cref="ITokenBucket.Consume"/> that accepts a <see cref="TimeSpan"/> timeout
|
||||
/// </summary>
|
||||
public static void Consume(this ITokenBucket bucket, long tokens, TimeSpan timeout)
|
||||
{
|
||||
bucket.Consume(tokens, (long) timeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ITokenBucket"/> that does not enforce rate limiting
|
||||
/// </summary>
|
||||
private class NullTokenBucket : ITokenBucket
|
||||
{
|
||||
public long Capacity => long.MaxValue;
|
||||
public long AvailableTokens => long.MaxValue;
|
||||
public bool TryConsume(long tokens) { return true; }
|
||||
public void Consume(long tokens, long timeout = Timeout.Infinite) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user