public abstract class AbstractBucket extends Object implements Bucket, BlockingBucket, SchedulingBucket
Modifier and Type | Field and Description |
---|---|
protected static long |
INFINITY_DURATION |
protected static long |
UNLIMITED_AMOUNT |
Constructor and Description |
---|
AbstractBucket(BucketListener listener) |
Modifier and Type | Method and Description |
---|---|
void |
addTokens(long tokensToAdd)
Add tokensToAdd to bucket.
|
protected abstract void |
addTokensImpl(long tokensToAdd) |
protected abstract VerboseResult<Nothing> |
addTokensVerboseImpl(long tokensToAdd) |
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 <T> CompletableFuture<T> |
completedFuture(Supplier<T> supplier) |
void |
consume(long tokensToConsume,
BlockingStrategy blockingStrategy)
Consumes a specified number of tokens from the bucket.
|
CompletableFuture<Void> |
consume(long tokensToConsume,
ScheduledExecutorService scheduler)
Consumes the specified number of tokens from the bucket.
|
protected abstract long |
consumeAsMuchAsPossibleImpl(long limit) |
protected abstract VerboseResult<Long> |
consumeAsMuchAsPossibleVerboseImpl(long limit) |
long |
consumeIgnoringRateLimits(long tokens)
Consumes
tokens from bucket ignoring all limits. |
protected abstract long |
consumeIgnoringRateLimitsImpl(long tokensToConsume) |
protected abstract VerboseResult<Long> |
consumeIgnoringRateLimitsVerboseImpl(long tokensToConsume) |
void |
consumeUninterruptibly(long tokensToConsume,
UninterruptibleBlockingStrategy blockingStrategy)
Has same semantic with
BlockingBucket.consume(long, BlockingStrategy) but ignores interrupts(just restores interruption flag on exit). |
EstimationProbe |
estimateAbilityToConsume(long numTokens)
Estimates ability to consume a specified number of tokens.
|
protected abstract EstimationProbe |
estimateAbilityToConsumeImpl(long numTokens) |
protected abstract VerboseResult<EstimationProbe> |
estimateAbilityToConsumeVerboseImpl(long numTokens) |
static <T> CompletableFuture<T> |
failedFuture(Throwable t) |
void |
forceAddTokens(long tokensToAdd)
Add tokensToAdd to bucket.
|
protected abstract void |
forceAddTokensImpl(long tokensToAdd) |
protected abstract VerboseResult<Nothing> |
forceAddTokensVerboseImpl(long tokensToAdd) |
protected abstract VerboseResult<Long> |
getAvailableTokensVerboseImpl() |
protected BucketListener |
getListener() |
void |
replaceConfiguration(BucketConfiguration newConfiguration,
TokensInheritanceStrategy tokensInheritanceStrategy)
Replaces configuration of this bucket.
|
protected abstract void |
replaceConfigurationImpl(BucketConfiguration newConfiguration,
TokensInheritanceStrategy tokensInheritanceStrategy) |
protected abstract VerboseResult<Nothing> |
replaceConfigurationVerboseImpl(BucketConfiguration newConfiguration,
TokensInheritanceStrategy tokensInheritanceStrategy) |
protected abstract long |
reserveAndCalculateTimeToSleepImpl(long tokensToConsume,
long waitIfBusyNanos) |
protected abstract VerboseResult<Nothing> |
resetVerboseImpl() |
boolean |
tryConsume(long tokensToConsume)
Tries to consume a specified number of tokens from this bucket.
|
boolean |
tryConsume(long tokensToConsume,
long maxWaitTimeNanos,
BlockingStrategy blockingStrategy)
Tries to consume a specified number of tokens from the bucket.
|
CompletableFuture<Boolean> |
tryConsume(long tokensToConsume,
long maxWaitTimeNanos,
ScheduledExecutorService scheduler)
Tries to consume the specified number of tokens from the bucket.
|
ConsumptionProbe |
tryConsumeAndReturnRemaining(long tokensToConsume)
Tries to consume a specified number of tokens from this bucket.
|
protected abstract ConsumptionProbe |
tryConsumeAndReturnRemainingTokensImpl(long tokensToConsume) |
protected abstract VerboseResult<ConsumptionProbe> |
tryConsumeAndReturnRemainingTokensVerboseImpl(long tokensToConsume) |
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 . |
protected abstract boolean |
tryConsumeImpl(long tokensToConsume) |
boolean |
tryConsumeUninterruptibly(long tokensToConsume,
long maxWaitTimeNanos,
UninterruptibleBlockingStrategy blockingStrategy)
Has same semantic with
BlockingBucket.tryConsume(long, long, BlockingStrategy) but ignores interrupts(just restores interruption flag on exit). |
protected abstract VerboseResult<Boolean> |
tryConsumeVerboseImpl(long tokensToConsume) |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
builder, getAvailableTokens, reset, toListenable
consume, consumeUninterruptibly, tryConsume, tryConsume, tryConsume, tryConsumeUninterruptibly, tryConsumeUninterruptibly, tryConsumeUninterruptibly
tryConsume
protected static long INFINITY_DURATION
protected static long UNLIMITED_AMOUNT
public AbstractBucket(BucketListener listener)
protected abstract long consumeAsMuchAsPossibleImpl(long limit)
protected abstract boolean tryConsumeImpl(long tokensToConsume)
protected abstract ConsumptionProbe tryConsumeAndReturnRemainingTokensImpl(long tokensToConsume)
protected abstract EstimationProbe estimateAbilityToConsumeImpl(long numTokens)
protected abstract long reserveAndCalculateTimeToSleepImpl(long tokensToConsume, long waitIfBusyNanos)
protected abstract void addTokensImpl(long tokensToAdd)
protected abstract void forceAddTokensImpl(long tokensToAdd)
protected abstract void replaceConfigurationImpl(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
protected abstract long consumeIgnoringRateLimitsImpl(long tokensToConsume)
protected abstract VerboseResult<Long> consumeAsMuchAsPossibleVerboseImpl(long limit)
protected abstract VerboseResult<Boolean> tryConsumeVerboseImpl(long tokensToConsume)
protected abstract VerboseResult<ConsumptionProbe> tryConsumeAndReturnRemainingTokensVerboseImpl(long tokensToConsume)
protected abstract VerboseResult<EstimationProbe> estimateAbilityToConsumeVerboseImpl(long numTokens)
protected abstract VerboseResult<Long> getAvailableTokensVerboseImpl()
protected abstract VerboseResult<Nothing> addTokensVerboseImpl(long tokensToAdd)
protected abstract VerboseResult<Nothing> forceAddTokensVerboseImpl(long tokensToAdd)
protected abstract VerboseResult<Nothing> resetVerboseImpl()
protected abstract VerboseResult<Nothing> replaceConfigurationVerboseImpl(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
protected abstract VerboseResult<Long> consumeIgnoringRateLimitsVerboseImpl(long tokensToConsume)
public SchedulingBucket asScheduler()
Bucket
ScheduledExecutorService
in case of lack of tokens.asScheduler
in interface Bucket
SchedulingBucket
public VerboseBucket asVerbose()
Bucket
public BlockingBucket asBlocking()
Bucket
asBlocking
in interface Bucket
BlockingBucket
public boolean tryConsume(long tokensToConsume)
Bucket
tryConsume
in interface Bucket
tokensToConsume
- The number of tokens to consume from the bucket, must be a positive number.true
if the tokens were consumed, false
otherwise.public boolean tryConsume(long tokensToConsume, long maxWaitTimeNanos, BlockingStrategy blockingStrategy) throws InterruptedException
BlockingBucket
The algorithm is following:
maxWaitTimeNanos
nanoseconds,
then consumes nothing and returns false immediately.
maxWaitTimeNanos
nanoseconds,
then tokens consumed(reserved in fair manner) from bucket and current thread blocked for a time required to close deficit,
after unblocking method returns true.
Note: If InterruptedException happen when thread was blocked
then tokens will be not returned back to bucket,
but you can use Bucket.addTokens(long)
to returned tokens back.
tryConsume
in interface BlockingBucket
tokensToConsume
- The number of tokens to consume from the bucket.maxWaitTimeNanos
- limit of time(in nanoseconds) which thread can wait.blockingStrategy
- specifies the way to block current thread to amount of time required to refill missed number of tokens in the bucketnumTokens
has been consumed or false when numTokens
has not been consumedInterruptedException
- in case of current thread has been interrupted during the waitingpublic boolean tryConsumeUninterruptibly(long tokensToConsume, long maxWaitTimeNanos, UninterruptibleBlockingStrategy blockingStrategy)
BlockingBucket
BlockingBucket.tryConsume(long, long, BlockingStrategy)
but ignores interrupts(just restores interruption flag on exit).tryConsumeUninterruptibly
in interface BlockingBucket
tokensToConsume
- The number of tokens to consume from the bucket.maxWaitTimeNanos
- limit of time(in nanoseconds) which thread can wait.blockingStrategy
- specifies the way to block current thread to amount of time required to refill missed number of tokens in the bucketnumTokens
has been consumed or false when numTokens
has not been consumedBlockingBucket.tryConsume(long, long, BlockingStrategy)
public void consume(long tokensToConsume, BlockingStrategy blockingStrategy) throws InterruptedException
BlockingBucket
The algorithm is following:
Bucket.addTokens(long)
to returned tokens back.
consume
in interface BlockingBucket
tokensToConsume
- The number of tokens to consume from the bucket.blockingStrategy
- specifies the way to block current thread to amount of time required to refill missed number of tokens in the bucketInterruptedException
- in case of current thread has been interrupted during the waitingpublic void consumeUninterruptibly(long tokensToConsume, UninterruptibleBlockingStrategy blockingStrategy)
BlockingBucket
BlockingBucket.consume(long, BlockingStrategy)
but ignores interrupts(just restores interruption flag on exit).consumeUninterruptibly
in interface BlockingBucket
tokensToConsume
- The number of tokens to consume from the bucket.blockingStrategy
- specifies the way to block current thread to amount of time required to refill missed number of tokens in the bucketBlockingBucket.consume(long, BlockingStrategy)
public long consumeIgnoringRateLimits(long tokens)
Bucket
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)
consumeIgnoringRateLimits
in interface Bucket
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).
public long tryConsumeAsMuchAsPossible(long limit)
Bucket
limit
.tryConsumeAsMuchAsPossible
in interface Bucket
limit
- maximum number of tokens to consume, should be positive.public long tryConsumeAsMuchAsPossible()
Bucket
tryConsumeAsMuchAsPossible
in interface Bucket
public ConsumptionProbe tryConsumeAndReturnRemaining(long tokensToConsume)
Bucket
tryConsumeAndReturnRemaining
in interface Bucket
tokensToConsume
- 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.public EstimationProbe estimateAbilityToConsume(long numTokens)
Bucket
estimateAbilityToConsume
in interface Bucket
numTokens
- The number of tokens to consume, must be a positive number.EstimationProbe
which describes the ability to consume.public void addTokens(long tokensToAdd)
Bucket
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);
}
};
public void forceAddTokens(long tokensToAdd)
Bucket
Bucket.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);
}
};
forceAddTokens
in interface Bucket
tokensToAdd
- number of tokens to addpublic void replaceConfiguration(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
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 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.
replaceConfiguration
in interface Bucket
newConfiguration
- the new configurationtokensInheritanceStrategy
- specifies the rules for inheritance of available tokenspublic CompletableFuture<Boolean> tryConsume(long tokensToConsume, long maxWaitTimeNanos, ScheduledExecutorService scheduler)
SchedulingBucket
The algorithm for all type of buckets is following:
ScheduledExecutorService.schedule(Runnable, long, TimeUnit)
,
when delay equals to time required to refill the deficit of tokens. After scheduler executes task the future completed by true.
CompletableFuture.thenApplyAsync(Function, Executor)
.tryConsume
in interface SchedulingBucket
tokensToConsume
- The number of tokens to consume from the bucket.maxWaitTimeNanos
- limit of time(in nanoseconds) which thread can wait.scheduler
- used to delayed future completionpublic CompletableFuture<Void> consume(long tokensToConsume, ScheduledExecutorService scheduler)
SchedulingBucket
The algorithm for all type of buckets is following:
ScheduledExecutorService.schedule(Runnable, long, TimeUnit)
,
when delay equals to time required to refill the deficit of tokens. After scheduler executes task the future completed.
CompletableFuture.thenApplyAsync(Function, Executor)
.consume
in interface SchedulingBucket
tokensToConsume
- The number of tokens to consume from the bucket.scheduler
- used to delayed future completionprotected BucketListener getListener()
public static <T> CompletableFuture<T> completedFuture(Supplier<T> supplier)
public static <T> CompletableFuture<T> failedFuture(Throwable t)
Copyright © 2022. All rights reserved.