public interface Bucket
Modifier and Type | Method and Description |
---|---|
void |
addTokens(long tokensToAdd)
Add tokensToAdd to bucket.
|
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.
|
SchedulingBucket |
asScheduler()
Returns the scheduling API for this bucket, that provides operations which can delay user operation via
ScheduledExecutorService in case of lack of tokens. |
VerboseBucket |
asVerbose()
Returns the verbose API for this bucket.
|
static LocalBucketBuilder |
builder()
Creates the new builder of in-memory buckets.
|
long |
consumeIgnoringRateLimits(long tokens)
Consumes
tokens from bucket ignoring all limits. |
EstimationProbe |
estimateAbilityToConsume(long numTokens)
Estimates ability to consume a specified number of tokens.
|
void |
forceAddTokens(long tokensToAdd)
Add tokensToAdd to bucket.
|
long |
getAvailableTokens()
Returns amount of available tokens in this bucket.
|
void |
replaceConfiguration(BucketConfiguration newConfiguration,
TokensInheritanceStrategy tokensInheritanceStrategy)
Replaces configuration of this bucket.
|
Bucket |
toListenable(BucketListener listener)
Returns new copy of this bucket instance decorated by
listener . |
boolean |
tryConsume(long numTokens)
Tries to consume a specified number of tokens from this bucket.
|
ConsumptionProbe |
tryConsumeAndReturnRemaining(long numTokens)
Tries to consume a specified number of tokens from this bucket.
|
long |
tryConsumeAsMuchAsPossible()
Tries to consume as much tokens from this bucket as available at the moment of invocation.
|
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 by
limit . |
static LocalBucketBuilder builder()
LocalBucketBuilder
BlockingBucket asBlocking()
BlockingBucket
SchedulingBucket asScheduler()
ScheduledExecutorService
in case of lack of tokens.SchedulingBucket
VerboseBucket asVerbose()
boolean tryConsume(long numTokens)
numTokens
- The number of tokens to consume from the bucket, must be a positive number.true
if the tokens were consumed, false
otherwise.long consumeIgnoringRateLimits(long tokens)
tokens
from 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:
asScheduler().consume(tokens)
tokens
- amount of tokens that should be consumed from bucket.consumeIgnoringRateLimits(2)
,
after invocation there are 3 tokens remain in the bucket, since limits were not violated zero returned as result.consumeIgnoringRateLimits(6)
called.
300_000_000 will be returned as result and available tokens in the bucket will became -3, and any variation of tryConsume...
will not be successful for 400 milliseconds(time required to refill amount of available tokens until 1).
ConsumptionProbe tryConsumeAndReturnRemaining(long numTokens)
numTokens
- The number of tokens to consume from the bucket, must be a positive number.ConsumptionProbe
which describes both result of consumption and tokens remaining in the bucket after consumption.EstimationProbe estimateAbilityToConsume(long numTokens)
numTokens
- The number of tokens to consume, must be a positive number.EstimationProbe
which describes the ability to consume.long tryConsumeAsMuchAsPossible()
long tryConsumeAsMuchAsPossible(long limit)
limit
.limit
- maximum number of tokens to consume, should be positive.void addTokens(long tokensToAdd)
newTokens = Math.min(capacity, currentTokens + tokensToAdd)in other words resulted number of tokens never exceeds capacity independent of tokensToAdd.
Bucket wallet;
...
if(wallet.tryConsume(50)) {// get 50 cents from wallet
try {
buyCocaCola();
} catch(NoCocaColaException e) {
// return money to wallet
wallet.addTokens(50);
}
};
tokensToAdd
- number of tokens to addvoid forceAddTokens(long tokensToAdd)
addTokens(long)
usage of this method can lead to overflow bucket capacity.
Bucket wallet;
...
if(wallet.tryConsume(50)) {// get 50 cents from wallet
try {
buyCocaCola();
} catch(NoCocaColaException e) {
// return money to wallet
wallet.addTokens(50);
}
};
tokensToAdd
- number of tokens to addlong getAvailableTokens()
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.
void replaceConfiguration(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
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 between TokensInheritanceStrategy.PROPORTIONALLY
and TokensInheritanceStrategy.AS_IS
, read documentation about both with strong attention.
There is another problem when you are choosing TokensInheritanceStrategy.PROPORTIONALLY
and TokensInheritanceStrategy.AS_IS
and bucket has more then one bandwidth.
For example how does replaceConfiguration implementation should bind bandwidths to each other in the following example?
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);
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)).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:
TokensInheritanceStrategy.RESET
strategy 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.
newConfiguration
- the new configurationtokensInheritanceStrategy
- specifies the rules for inheritance of available tokensBucket toListenable(BucketListener listener)
listener
.
The created bucket will share same tokens with source bucket and vice versa.
See javadocs for BucketListener
in order to understand semantic of listener.listener
- the listener of bucket events.listener
Copyright © 2022. All rights reserved.