Class AbstractBucket

java.lang.Object
io.github.bucket4j.AbstractBucket
All Implemented Interfaces:
Bucket
Direct Known Subclasses:
DefaultBucketProxy, LockFreeBucket, SynchronizedBucket, ThreadUnsafeBucket

public abstract class AbstractBucket extends Object implements Bucket
  • Field Details

  • Constructor Details

  • Method Details

    • consumeAsMuchAsPossibleImpl

      protected abstract long consumeAsMuchAsPossibleImpl(long limit)
    • tryConsumeImpl

      protected abstract boolean tryConsumeImpl(long tokensToConsume)
    • tryConsumeAndReturnRemainingTokensImpl

      protected abstract ConsumptionProbe tryConsumeAndReturnRemainingTokensImpl(long tokensToConsume)
    • estimateAbilityToConsumeImpl

      protected abstract EstimationProbe estimateAbilityToConsumeImpl(long numTokens)
    • reserveAndCalculateTimeToSleepImpl

      protected abstract long reserveAndCalculateTimeToSleepImpl(long tokensToConsume, long waitIfBusyNanos)
    • addTokensImpl

      protected abstract void addTokensImpl(long tokensToAdd)
    • forceAddTokensImpl

      protected abstract void forceAddTokensImpl(long tokensToAdd)
    • replaceConfigurationImpl

      protected abstract void replaceConfigurationImpl(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
    • consumeIgnoringRateLimitsImpl

      protected abstract long consumeIgnoringRateLimitsImpl(long tokensToConsume)
    • consumeAsMuchAsPossibleVerboseImpl

      protected abstract VerboseResult<Long> consumeAsMuchAsPossibleVerboseImpl(long limit)
    • tryConsumeVerboseImpl

      protected abstract VerboseResult<Boolean> tryConsumeVerboseImpl(long tokensToConsume)
    • tryConsumeAndReturnRemainingTokensVerboseImpl

      protected abstract VerboseResult<ConsumptionProbe> tryConsumeAndReturnRemainingTokensVerboseImpl(long tokensToConsume)
    • estimateAbilityToConsumeVerboseImpl

      protected abstract VerboseResult<EstimationProbe> estimateAbilityToConsumeVerboseImpl(long numTokens)
    • getAvailableTokensVerboseImpl

      protected abstract VerboseResult<Long> getAvailableTokensVerboseImpl()
    • addTokensVerboseImpl

      protected abstract VerboseResult<Nothing> addTokensVerboseImpl(long tokensToAdd)
    • forceAddTokensVerboseImpl

      protected abstract VerboseResult<Nothing> forceAddTokensVerboseImpl(long tokensToAdd)
    • resetVerboseImpl

      protected abstract VerboseResult<Nothing> resetVerboseImpl()
    • replaceConfigurationVerboseImpl

      protected abstract VerboseResult<Nothing> replaceConfigurationVerboseImpl(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
    • consumeIgnoringRateLimitsVerboseImpl

      protected abstract VerboseResult<Long> consumeIgnoringRateLimitsVerboseImpl(long tokensToConsume)
    • reserveAndCalculateTimeToSleepVerboseImpl

      protected abstract VerboseResult<Long> reserveAndCalculateTimeToSleepVerboseImpl(long tokensToConsume, long maxWaitTimeNanos)
    • asScheduler

      public SchedulingBucket asScheduler()
      Description copied from interface: Bucket
      Returns the scheduling API for this bucket, that provides operations which can delay user operation via ScheduledExecutorService in case of lack of tokens.
      Specified by:
      asScheduler in interface Bucket
      Returns:
      the scheduling API for this bucket.
      See Also:
    • asVerbose

      public VerboseBucket asVerbose()
      Description copied from interface: Bucket
      Returns the verbose API for this bucket.
      Specified by:
      asVerbose in interface Bucket
      Returns:
      the verbose API for this bucket.
    • asBlocking

      public BlockingBucket asBlocking()
      Description copied from interface: Bucket
      Returns the blocking API for this bucket, that provides operations which are able to block caller thread in case of lack of tokens.
      Specified by:
      asBlocking in interface Bucket
      Returns:
      the blocking API for this bucket.
      See Also:
    • tryConsume

      public boolean tryConsume(long tokensToConsume)
      Description copied from interface: Bucket
      Tries to consume a specified number of tokens from this bucket.
      Specified by:
      tryConsume in interface Bucket
      Parameters:
      tokensToConsume - The number of tokens to consume from the bucket, must be a positive number.
      Returns:
      true if the tokens were consumed, false otherwise.
    • consumeIgnoringRateLimits

      public long consumeIgnoringRateLimits(long tokens)
      Description copied from interface: Bucket
      Consumes 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:

      • 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)
      Specified by:
      consumeIgnoringRateLimits in interface Bucket
      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 of tryConsume... will not be successful for 400 milliseconds(time required to refill amount of available tokens until 1).
    • tryConsumeAsMuchAsPossible

      public long tryConsumeAsMuchAsPossible(long limit)
      Description copied from interface: Bucket
      Tries to consume as many tokens from bucket as available in the bucket at the moment of invocation, but tokens which should be consumed is limited by limit.
      Specified by:
      tryConsumeAsMuchAsPossible in interface Bucket
      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.
    • tryConsumeAsMuchAsPossible

      public long tryConsumeAsMuchAsPossible()
      Description copied from interface: Bucket
      Tries to consume as many tokens from this bucket as available at the moment of invocation.
      Specified by:
      tryConsumeAsMuchAsPossible in interface Bucket
      Returns:
      number of tokens which has been consumed, or zero if was consumed nothing.
    • tryConsumeAndReturnRemaining

      public ConsumptionProbe tryConsumeAndReturnRemaining(long tokensToConsume)
      Description copied from interface: Bucket
      Tries to consume a specified number of tokens from this bucket.
      Specified by:
      tryConsumeAndReturnRemaining in interface Bucket
      Parameters:
      tokensToConsume - The number of tokens to consume from the bucket, must be a positive number.
      Returns:
      ConsumptionProbe which describes both result of consumption and tokens remaining in the bucket after consumption.
    • estimateAbilityToConsume

      public EstimationProbe estimateAbilityToConsume(long numTokens)
      Description copied from interface: Bucket
      Estimates ability to consume a specified number of tokens.
      Specified by:
      estimateAbilityToConsume in interface Bucket
      Parameters:
      numTokens - The number of tokens to consume, must be a positive number.
      Returns:
      EstimationProbe which describes the ability to consume.
    • addTokens

      public void addTokens(long tokensToAdd)
      Description copied from interface: Bucket
      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);
               }
            };
       
      Specified by:
      addTokens in interface Bucket
      Parameters:
      tokensToAdd - number of tokens to add
    • forceAddTokens

      public void forceAddTokens(long tokensToAdd)
      Description copied from interface: Bucket
      Add tokensToAdd to bucket. In opposite to Bucket.addTokens(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);
               }
            };
       
      Specified by:
      forceAddTokens in interface Bucket
      Parameters:
      tokensToAdd - number of tokens to add
    • replaceConfiguration

      public void replaceConfiguration(BucketConfiguration newConfiguration, TokensInheritanceStrategy tokensInheritanceStrategy)
      Description copied from interface: Bucket
      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 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 than 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 = BucketConfiguration.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 on from order. Instead of inventing the backward magic Bucket4j provides to you ability to deap control of this process by specifying identifiers for bandwidth, so in case of multiple bandwidth configuration 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 = BucketConfiguration.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.RESET strategy will be applied for tokens migration during config replacement for bandwidth which has no bound bandwidth with same ID in previous configuration, independently of strategy that was requested.
      Specified by:
      replaceConfiguration in interface Bucket
      Parameters:
      newConfiguration - the new configuration
      tokensInheritanceStrategy - specifies the rules for inheritance of available tokens
    • getListener

      protected BucketListener getListener()
    • completedFuture

      public static <T> CompletableFuture<T> completedFuture(Supplier<T> supplier)
    • failedFuture

      public static <T> CompletableFuture<T> failedFuture(Throwable t)