RateLimiter
Date: 2016-05-24

com.google.common.util.concurrent

## Class RateLimiter

- java.lang.Object
- - com.google.common.util.concurrent.RateLimiter

-     @ThreadSafe
      @Beta
      public abstract class RateLimiter
      extends java.lang.Object

  A rate limiter. Conceptually, a rate limiter distributes permits at a configurable rate. Each `acquire()` blocks if necessary until a permit is available, and then takes it. Once acquired, permits need not be released.

  Rate limiters are often used to restrict the rate at which some physical or logical resource is accessed. This is in contrast to `Semaphore` which restricts the number of concurrent accesses instead of the rate (note though that concurrency and rate are closely related, e.g. see Little's Law).

  A `RateLimiter` is defined primarily by the rate at which permits are issued. Absent additional configuration, permits will be distributed at a fixed rate, defined in terms of permits per second. Permits will be distributed smoothly, with the delay between individual permits being adjusted to ensure that the configured rate is maintained.

  It is possible to configure a `RateLimiter` to have a warmup period during which time the permits issued each second steadily increases until it hits the stable rate.

  As an example, imagine that we have a list of tasks to execute, but we don't want to submit more than 2 per second:

        final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
        void submitTasks(List<Runnable> tasks, Executor executor) {
          for (Runnable task : tasks) {
            rateLimiter.acquire(); // may wait
            executor.execute(task);
          }
        }

  As another example, imagine that we produce a stream of data, and we want to cap it at 5kb per second. This could be accomplished by requiring a permit per byte, and specifying a rate of 5000 permits per second:

        final RateLimiter rateLimiter = RateLimiter.create(5000.0); // rate = 5000 permits per second
        void submitPacket(byte[] packet) {
          rateLimiter.acquire(packet.length);
          networkService.send(packet);
        }

  It is important to note that the number of permits requested never affects the throttling of the request itself (an invocation to `acquire(1)` and an invocation to `acquire(1000)` will result in exactly the same throttling, if any), but it affects the throttling of the next request. I.e., if an expensive task arrives at an idle RateLimiter, it will be granted immediately, but it is the next request that will experience extra throttling, thus paying for the cost of the expensive task.

  Note: `RateLimiter` does not provide fairness guarantees.

  Since:
    13.0

- - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `double` | `acquire()` Acquires a single permit from this `RateLimiter`, blocking until the request can be granted.
    `double` | `acquire(int permits)` Acquires the given number of permits from this `RateLimiter`, blocking until the request can be granted.
    `static RateLimiter` | `create(double permitsPerSecond)` Creates a `RateLimiter` with the specified stable throughput, given as "permits per second" (commonly referred to as QPS, queries per second).
    `static RateLimiter` | `create(double permitsPerSecond, long warmupPeriod, java.util.concurrent.TimeUnit unit)` Creates a `RateLimiter` with the specified stable throughput, given as "permits per second" (commonly referred to as QPS, queries per second), and a warmup period, during which the `RateLimiter` smoothly ramps up its rate, until it reaches its maximum rate at the end of the period (as long as there are enough requests to saturate it).
    `double` | `getRate()` Returns the stable rate (as `permits per seconds`) with which this `RateLimiter` is configured with.
    `void` | `setRate(double permitsPerSecond)` Updates the stable rate of this `RateLimiter`, that is, the `permitsPerSecond` argument provided in the factory method that constructed the `RateLimiter`.
    `java.lang.String` | `toString()`
    `boolean` | `tryAcquire()` Acquires a permit from this `RateLimiter` if it can be acquired immediately without delay.
    `boolean` | `tryAcquire(int permits)` Acquires permits from this `RateLimiter` if it can be acquired immediately without delay.
    `boolean` | `tryAcquire(int permits, long timeout, java.util.concurrent.TimeUnit unit)` Acquires the given number of permits from this `RateLimiter` if it can be obtained without exceeding the specified `timeout`, or returns `false` immediately (without waiting) if the permits would not have been granted before the timeout expired.
    `boolean` | `tryAcquire(long timeout, java.util.concurrent.TimeUnit unit)` Acquires a permit from this `RateLimiter` if it can be obtained without exceeding the specified `timeout`, or returns `false` immediately (without waiting) if the permit would not have been granted before the timeout expired.

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- - ### Method Detail

    - #### create

          public static RateLimiter create(double permitsPerSecond)

      Creates a `RateLimiter` with the specified stable throughput, given as "permits per second" (commonly referred to as QPS, queries per second).

      The returned `RateLimiter` ensures that on average no more than `permitsPerSecond` are issued during any given second, with sustained requests being smoothly spread over each second. When the incoming request rate exceeds `permitsPerSecond` the rate limiter will release one permit every `(1.0 / permitsPerSecond)` seconds. When the rate limiter is unused, bursts of up to `permitsPerSecond` permits will be allowed, with subsequent requests being smoothly limited at the stable rate of `permitsPerSecond`.

      Parameters:
        `permitsPerSecond` - the rate of the returned `RateLimiter`, measured in how many permits become available per second
      Throws:
        `java.lang.IllegalArgumentException` - if `permitsPerSecond` is negative or zero

    - #### create

          public static RateLimiter create(double permitsPerSecond,
                           long warmupPeriod,
                           java.util.concurrent.TimeUnit unit)

      Creates a `RateLimiter` with the specified stable throughput, given as "permits per second" (commonly referred to as QPS, queries per second), and a warmup period, during which the `RateLimiter` smoothly ramps up its rate, until it reaches its maximum rate at the end of the period (as long as there are enough requests to saturate it). Similarly, if the `RateLimiter` is left unused for a duration of `warmupPeriod`, it will gradually return to its "cold" state, i.e. it will go through the same warming up process as when it was first created.

      The returned `RateLimiter` is intended for cases where the resource that actually fulfills the requests (e.g., a remote server) needs "warmup" time, rather than being immediately accessed at the stable (maximum) rate.

      The returned `RateLimiter` starts in a "cold" state (i.e. the warmup period will follow), and if it is left unused for long enough, it will return to that state.

      Parameters:
        `permitsPerSecond` - the rate of the returned `RateLimiter`, measured in how many permits become available per second
        `warmupPeriod` - the duration of the period where the `RateLimiter` ramps up its rate, before reaching its stable (maximum) rate
        `unit` - the time unit of the warmupPeriod argument
      Throws:
        `java.lang.IllegalArgumentException` - if `permitsPerSecond` is negative or zero or `warmupPeriod` is negative

    - #### setRate

          public final void setRate(double permitsPerSecond)

      Updates the stable rate of this `RateLimiter`, that is, the `permitsPerSecond` argument provided in the factory method that constructed the `RateLimiter`. Currently throttled threads will not be awakened as a result of this invocation, thus they do not observe the new rate; only subsequent requests will.

      Note though that, since each request repays (by waiting, if necessary) the cost of the previous request, this means that the very next request after an invocation to `setRate` will not be affected by the new rate; it will pay the cost of the previous request, which is in terms of the previous rate.

      The behavior of the `RateLimiter` is not modified in any other way, e.g. if the `RateLimiter` was configured with a warmup period of 20 seconds, it still has a warmup period of 20 seconds after this method invocation.

      Parameters:
        `permitsPerSecond` - the new stable rate of this `RateLimiter`
      Throws:
        `java.lang.IllegalArgumentException` - if `permitsPerSecond` is negative or zero

    - #### getRate

          public final double getRate()

      Returns the stable rate (as `permits per seconds`) with which this `RateLimiter` is configured with. The initial value of this is the same as the `permitsPerSecond` argument passed in the factory method that produced this `RateLimiter`, and it is only updated after invocations to setRate(double).

    - #### acquire

          public double acquire()

      Acquires a single permit from this `RateLimiter`, blocking until the request can be granted. Tells the amount of time slept, if any.

      This method is equivalent to `acquire(1)`.

      Returns:
        time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
      Since:
        16.0 (present in 13.0 with `void` return type})

    - #### acquire

          public double acquire(int permits)

      Acquires the given number of permits from this `RateLimiter`, blocking until the request can be granted. Tells the amount of time slept, if any.
      Parameters:
        `permits` - the number of permits to acquire
      Returns:
        time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
      Throws:
        `java.lang.IllegalArgumentException` - if the requested number of permits is negative or zero
      Since:
        16.0 (present in 13.0 with `void` return type})

    - #### tryAcquire

          public boolean tryAcquire(long timeout,
                           java.util.concurrent.TimeUnit unit)

      Acquires a permit from this `RateLimiter` if it can be obtained without exceeding the specified `timeout`, or returns `false` immediately (without waiting) if the permit would not have been granted before the timeout expired.

      This method is equivalent to `tryAcquire(1, timeout, unit)`.

      Parameters:
        `timeout` - the maximum time to wait for the permit. Negative values are treated as zero.
        `unit` - the time unit of the timeout argument
      Returns:
        `true` if the permit was acquired, `false` otherwise
      Throws:
        `java.lang.IllegalArgumentException` - if the requested number of permits is negative or zero

    - #### tryAcquire

          public boolean tryAcquire(int permits)

      Acquires permits from this `RateLimiter` if it can be acquired immediately without delay.

      This method is equivalent to `tryAcquire(permits, 0, anyUnit)`.

      Parameters:
        `permits` - the number of permits to acquire
      Returns:
        `true` if the permits were acquired, `false` otherwise
      Throws:
        `java.lang.IllegalArgumentException` - if the requested number of permits is negative or zero
      Since:
        14.0

    - #### tryAcquire

          public boolean tryAcquire()

      Acquires a permit from this `RateLimiter` if it can be acquired immediately without delay.

      This method is equivalent to `tryAcquire(1)`.

      Returns:
        `true` if the permit was acquired, `false` otherwise
      Since:
        14.0

    - #### tryAcquire

          public boolean tryAcquire(int permits,
                           long timeout,
                           java.util.concurrent.TimeUnit unit)

      Acquires the given number of permits from this `RateLimiter` if it can be obtained without exceeding the specified `timeout`, or returns `false` immediately (without waiting) if the permits would not have been granted before the timeout expired.
      Parameters:
        `permits` - the number of permits to acquire
        `timeout` - the maximum time to wait for the permits. Negative values are treated as zero.
        `unit` - the time unit of the timeout argument
      Returns:
        `true` if the permits were acquired, `false` otherwise
      Throws:
        `java.lang.IllegalArgumentException` - if the requested number of permits is negative or zero

    - #### toString

          public java.lang.String toString()

      Overrides:
        `toString` in class `java.lang.Object`