Class AsyncTokenBucket
- Direct Known Subclasses:
DynamicRateAsyncTokenBucket
LongAdder class is used in the hot path to hold the sum of consumed tokens.
It is eventually consistent, meaning that the tokens are not updated on every call to the "consumeTokens" method.
Main usage flow: 1. Tokens are consumed by invoking the "consumeTokens" or "consumeTokensAndCheckIfContainsTokens" methods. 2. The "consumeTokensAndCheckIfContainsTokens" or "containsTokens" methods return false if there are no tokens available, indicating a need for throttling. 3. In case of throttling, the application should throttle in a way that is suitable for the use case and then call the "calculateThrottlingDuration" method to calculate the duration of the required pause. 4. After the pause duration, the application should verify if there are any available tokens by invoking the containsTokens method. If tokens are available, the application should cease throttling. However, if tokens are not available, the application should maintain the throttling and recompute the throttling duration. In a concurrent environment, it is advisable to use a throttling queue to ensure fair distribution of resources across throttled connections or clients. Once the throttling duration has elapsed, the application should select the next connection or client from the throttling queue to unthrottle. Before unthrottling, the application should check for available tokens. If tokens are still not available, the application should continue with throttling and repeat the throttling loop.
This class does not produce side effects outside its own scope. It functions similarly to a stateful function, akin to a counter function. In essence, it is a sophisticated counter. It can serve as a foundational component for constructing higher-level asynchronous rate limiter implementations, which require side effects for throttling.
To achieve optimal performance, pass a DefaultMonotonicSnapshotClock instance as the clock .
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final MonotonicSnapshotClockprotected final longThe resolution in nanoseconds.protected longThis field represents the number of tokens in the bucket. -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedAsyncTokenBucket(MonotonicSnapshotClock clockSource, long resolutionNanos) -
Method Summary
Modifier and TypeMethodDescriptionbuilder()longCalculate the required throttling duration in nanoseconds to fill up the bucket with the minimum amount of tokens.voidconsumeTokens(long consumeTokens) Eventually consume tokens from the bucket.booleanconsumeTokensAndCheckIfContainsTokens(long consumeTokens) Eventually consume tokens from the bucket and check if tokens remain available.booleanChecks if the bucket contains tokens.booleancontainsTokens(boolean forceUpdateTokens) Checks if the bucket contains tokens.abstract longabstract longgetRate()protected abstract longprotected abstract longfinal longReturns the current number of tokens in the bucket.static voidstatic voidprotected longtokens(boolean forceUpdateTokens) Returns the current token balance.
-
Field Details
-
DEFAULT_SNAPSHOT_CLOCK
-
tokens
protected volatile long tokensThis field represents the number of tokens in the bucket. It is eventually consistent, as the pendingConsumedTokens are subtracted from the total number of tokens at most once during each "tick" or "increment", when time advances according to the configured resolution. -
resolutionNanos
protected final long resolutionNanosThe resolution in nanoseconds. This is the amount of time that must pass before the tokens are updated.
-
-
Constructor Details
-
AsyncTokenBucket
-
-
Method Details
-
switchToConsistentTokensView
public static void switchToConsistentTokensView() -
resetToDefaultEventualConsistentTokensView
public static void resetToDefaultEventualConsistentTokensView() -
builder
-
builderForDynamicRate
-
getRatePeriodNanos
protected abstract long getRatePeriodNanos() -
getTargetAmountOfTokensAfterThrottling
protected abstract long getTargetAmountOfTokensAfterThrottling() -
consumeTokens
public void consumeTokens(long consumeTokens) Eventually consume tokens from the bucket. The number of tokens is eventually consistent with the configured granularity of resolutionNanos.- Parameters:
consumeTokens- the number of tokens to consume
-
consumeTokensAndCheckIfContainsTokens
public boolean consumeTokensAndCheckIfContainsTokens(long consumeTokens) Eventually consume tokens from the bucket and check if tokens remain available. The number of tokens is eventually consistent with the configured granularity of resolutionNanos. Therefore, the returned result is not definite.- Parameters:
consumeTokens- the number of tokens to consume- Returns:
- true if there is tokens remains, false if tokens are all consumed. The answer isn't definite since the comparison is made with eventually consistent token value.
-
tokens
protected long tokens(boolean forceUpdateTokens) Returns the current token balance. When forceUpdateTokens is true, the tokens balance is updated before returning. If forceUpdateTokens is false, the tokens balance could be updated if the last updated happened more than resolutionNanos nanoseconds ago.- Parameters:
forceUpdateTokens- if true, the tokens balance is updated before returning- Returns:
- the current token balance
-
calculateThrottlingDuration
public long calculateThrottlingDuration()Calculate the required throttling duration in nanoseconds to fill up the bucket with the minimum amount of tokens. This method shouldn't be called from the hot path since it calculates a consistent value for the tokens which isn't necessary on the hotpath. -
getCapacity
public abstract long getCapacity() -
getTokens
public final long getTokens()Returns the current number of tokens in the bucket. The token balance is updated if the configured resolutionNanos has passed since the last update. -
getRate
public abstract long getRate() -
containsTokens
public boolean containsTokens()Checks if the bucket contains tokens. The token balance is updated before the comparison if the configured resolutionNanos has passed since the last update. It's possible that the returned result is not definite since the token balance is eventually consistent.- Returns:
- true if the bucket contains tokens, false otherwise
-
containsTokens
public boolean containsTokens(boolean forceUpdateTokens) Checks if the bucket contains tokens. The token balance is updated before the comparison if the configured resolutionNanos has passed since the last update. The token balance is also updated when forceUpdateTokens is true. It's possible that the returned result is not definite since the token balance is eventually consistent.- Parameters:
forceUpdateTokens- if true, the token balance is updated before the comparison- Returns:
- true if the bucket contains tokens, false otherwise
-