-
- All Known Subinterfaces:
BucketProxy,LocalBucket
- All Known Implementing Classes:
AbstractBucket,DefaultBucketProxy,LockFreeBucket,SynchronizedBucket,ThreadUnsafeBucket
public interface BucketPerforms rate limiting using algorithm based on top of ideas of Token Bucket.
-
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Modifier and Type Method Description voidaddTokens(long tokensToAdd)Add tokensToAdd to bucket.BlockingBucketasBlocking()Returns the blocking API for this bucket, that provides operations which are able to block caller thread in case of lack of tokens.SchedulingBucketasScheduler()Returns the scheduling API for this bucket, that provides operations which can delay user operation viaScheduledExecutorServicein case of lack of tokens.VerboseBucketasVerbose()Returns the verbose API for this bucket.static LocalBucketBuilderbuilder()Creates the new builder of in-memory buckets.longconsumeIgnoringRateLimits(long tokens)Consumestokensfrom bucket ignoring all limits.EstimationProbeestimateAbilityToConsume(long numTokens)Estimates ability to consume a specified number of tokens.voidforceAddTokens(long tokensToAdd)Add tokensToAdd to bucket.longgetAvailableTokens()Returns amount of available tokens in this bucket.voidreplaceConfiguration(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)Replaces configuration of this bucket.voidreset()Reset all tokens up to maximum capacity.BuckettoListenable(BucketListener listener)Returns new copy of this bucket instance decorated bylistener.booleantryConsume(long numTokens)Tries to consume a specified number of tokens from this bucket.ConsumptionProbetryConsumeAndReturnRemaining(long numTokens)Tries to consume a specified number of tokens from this bucket.longtryConsumeAsMuchAsPossible()Tries to consume as much tokens from this bucket as available at the moment of invocation.longtryConsumeAsMuchAsPossible(long limit)Tries to consume as much tokens from bucket as available in the bucket at the moment of invocation, but tokens which should be consumed is limited bylimit.
-
-
-
Method Detail
-
builder
static LocalBucketBuilder builder()
Creates the new builder of in-memory buckets.- Returns:
- new instance of
LocalBucketBuilder
-
asBlocking
BlockingBucket asBlocking()
Returns the blocking API for this bucket, that provides operations which are able to block caller thread in case of lack of tokens.- Returns:
- the blocking API for this bucket.
- See Also:
BlockingBucket
-
asScheduler
SchedulingBucket asScheduler()
Returns the scheduling API for this bucket, that provides operations which can delay user operation viaScheduledExecutorServicein case of lack of tokens.- Returns:
- the scheduling API for this bucket.
- See Also:
SchedulingBucket
-
asVerbose
VerboseBucket asVerbose()
Returns the verbose API for this bucket.- Returns:
- the verbose API for this bucket.
-
tryConsume
boolean tryConsume(long numTokens)
Tries to consume a specified number of tokens from this bucket.- Parameters:
numTokens- The number of tokens to consume from the bucket, must be a positive number.- Returns:
trueif the tokens were consumed,falseotherwise.
-
consumeIgnoringRateLimits
long consumeIgnoringRateLimits(long tokens)
Consumestokensfrom bucket ignoring all limits. In result of this operation amount of tokens in the bucket could became negative. There are two possible reasons to use this method:- An operation with high priority should be executed independently of rate limits, but it should take effect to subsequent operation with bucket.
- You want to apply custom blocking strategy instead of default which applied on
asScheduler().consume(tokens)
- Parameters:
tokens- amount of tokens that should be consumed from bucket.- Returns:
- the amount of rate limit violation in nanoseconds calculated in following way:
- zero if rate limit was not violated. For example bucket had 5 tokens before invocation of
consumeIgnoringRateLimits(2), after invocation there are 3 tokens remain in the bucket, since limits were not violated zero returned as result. - Positive value which describes the amount of rate limit violation in nanoseconds.
For example bucket with limit 10 tokens per 1 second, currently has the 2 tokens available, last refill happen 100 milliseconds ago, and
consumeIgnoringRateLimits(6)called. 300_000_000 will be returned as result and available tokens in the bucket will became -3, and any variation oftryConsume...will not be successful for 400 milliseconds(time required to refill amount of available tokens until 1).
- zero if rate limit was not violated. For example bucket had 5 tokens before invocation of
-
tryConsumeAndReturnRemaining
ConsumptionProbe tryConsumeAndReturnRemaining(long numTokens)
Tries to consume a specified number of tokens from this bucket.- Parameters:
numTokens- The number of tokens to consume from the bucket, must be a positive number.- Returns:
ConsumptionProbewhich describes both result of consumption and tokens remaining in the bucket after consumption.
-
estimateAbilityToConsume
EstimationProbe estimateAbilityToConsume(long numTokens)
Estimates ability to consume a specified number of tokens.- Parameters:
numTokens- The number of tokens to consume, must be a positive number.- Returns:
EstimationProbewhich describes the ability to consume.
-
tryConsumeAsMuchAsPossible
long tryConsumeAsMuchAsPossible()
Tries to consume as much tokens from this bucket as available at the moment of invocation.- Returns:
- number of tokens which has been consumed, or zero if was consumed nothing.
-
tryConsumeAsMuchAsPossible
long tryConsumeAsMuchAsPossible(long limit)
Tries to consume as much tokens from bucket as available in the bucket at the moment of invocation, but tokens which should be consumed is limited bylimit.- Parameters:
limit- maximum number of tokens to consume, should be positive.- Returns:
- number of tokens which has been consumed, or zero if was consumed nothing.
-
addTokens
void addTokens(long tokensToAdd)
Add tokensToAdd to bucket. Resulted count of tokens are calculated by following formula:newTokens = Math.min(capacity, currentTokens + tokensToAdd)
in other words resulted number of tokens never exceeds capacity independent of tokensToAdd.Example of usage
The "compensating transaction" is one of obvious use case, when any piece of code consumed tokens from bucket, tried to do something and failed, the "addTokens" will be helpful to return tokens back to bucket:Bucket wallet; ... if(wallet.tryConsume(50)) {// get 50 cents from wallet try { buyCocaCola(); } catch(NoCocaColaException e) { // return money to wallet wallet.addTokens(50); } };- Parameters:
tokensToAdd- number of tokens to add
-
forceAddTokens
void forceAddTokens(long tokensToAdd)
Add tokensToAdd to bucket. In opposite toaddTokens(long)usage of this method can lead to overflow bucket capacity.Example of usage
The "compensating transaction" is one of obvious use case, when any piece of code consumed tokens from bucket, tried to do something and failed, the "addTokens" will be helpful to return tokens back to bucket:Bucket wallet; ... if(wallet.tryConsume(50)) {// get 50 cents from wallet try { buyCocaCola(); } catch(NoCocaColaException e) { // return money to wallet wallet.forceAddTokens(50); } };- Parameters:
tokensToAdd- number of tokens to add
-
reset
void reset()
Reset all tokens up to maximum capacity.
-
getAvailableTokens
long getAvailableTokens()
Returns amount of available tokens in this bucket.Typically you should avoid using of this method for, because available tokens can be changed by concurrent transactions for case of multithreaded/multi-process environment.
- Returns:
- amount of available tokens
-
replaceConfiguration
void replaceConfiguration(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
Replaces configuration of this bucket.The first hard problem of configuration replacement is making decision how to propagate available tokens from bucket with previous configuration to bucket with new configuration. If you don't care about previous bucket state then use
TokensInheritanceStrategy.RESET. But it becomes to a tricky problem when we expect that previous consumption(that has not been compensated by refill yet) should take effect to the bucket with new configuration. In this case you need to make a choice betweenTokensInheritanceStrategy.PROPORTIONALLYandTokensInheritanceStrategy.AS_IS, read documentation about both with strong attention.There is another problem when you are choosing
TokensInheritanceStrategy.PROPORTIONALLYandTokensInheritanceStrategy.AS_ISand bucket has more then one bandwidth. For example how does replaceConfiguration implementation should bind bandwidths to each other in the following example?
It is obviously that simple strategy - copying tokens by bandwidth index will not work well in this case, because of it highly depends from order. Instead of inventing the backward maggic Bucket4j provides to you ability to deap controll of this process by specifying identifiers for bandwidth, so in case of multiple bandwidth configuratoin replacement code can copy available tokens by bandwidth ID. So it is better to rewrite code above as following:Bucket bucket = Bucket.builder() .addLimit(Bandwidth.simple(10, Duration.ofSeconds(1))) .addLimit(Bandwidth.simple(10000, Duration.ofHours(1))) .build(); ... BucketConfiguration newConfiguration = BucketConfiguratiion.builder() .addLimit(Bandwidth.simple(5000, Duration.ofHours(1))) .addLimit(Bandwidth.simple(100, Duration.ofSeconds(10))) .build(); bucket.replaceConfiguration(newConfiguration, TokensInheritanceStrategy.AS_IS);Bucket bucket = Bucket.builder() .addLimit(Bandwidth.simple(10, Duration.ofSeconds(1)).withId("technical-limit")) .addLimit(Bandwidth.simple(10000, Duration.ofHours(1)).withId("business-limit")) .build(); ... BucketConfiguration newConfiguration = BucketConfiguratiion.builder() .addLimit(Bandwidth.simple(5000, Duration.ofHours(1)).withId("business-limit")) .addLimit(Bandwidth.simple(100, Duration.ofSeconds(10)).withId("technical-limit")) .build(); bucket.replaceConfiguration(newConfiguration, TokensInheritanceStrategy.AS_IS);There are following rules for bandwidth identifiers:
- By default bandwidth has null identifier.
- null value of identifier equals to another null value if and only if there is only one bandwidth with null identifier.
- If identifier for bandwidth is specified then it must has unique in the bucket. Bucket does not allow to create several bandwidth with same ID.
-
TokensInheritanceStrategy.RESETstrategy will be applied for tokens migration during config replacement for bandwidth which has no bound bandwidth with same ID in previous configuration, idependently of strategy that was requested.
- Parameters:
newConfiguration- the new configurationtokensInheritanceStrategy- specifies the rules for inheritance of available tokens
-
toListenable
Bucket toListenable(BucketListener listener)
Returns new copy of this bucket instance decorated bylistener. The created bucket will share same tokens with source bucket and vice versa. See javadocs forBucketListenerin order to understand semantic of listener.- Parameters:
listener- the listener of bucket events.- Returns:
- new bucket instance decorated by
listener
-
-