leaky-bucket 0.8.2

Futures-aware rate limiter implementation.
Documentation
# leaky-bucket

[![Documentation](https://docs.rs/leaky-bucket/badge.svg)](https://docs.rs/leaky-bucket)
[![Crates](https://img.shields.io/crates/v/leaky-bucket.svg)](https://crates.io/crates/leaky-bucket)
[![Actions Status](https://github.com/udoprog/leaky-bucket/workflows/Rust/badge.svg)](https://github.com/udoprog/leaky-bucket/actions)

A token-based rate limiter based on the [leaky bucket] algorithm.

If the tokens are already available, the acquisition will be instant through
a fast path, and the acquired number of tokens will be added to the bucket.

If the bucket overflows (i.e. goes over max), the task that tried to acquire
the tokens will be suspended until the required number of tokens has been
added.

### Usage

Add the following to your `Cargo.toml`:

```toml
leaky-bucket = "0.8.2"
```

### Example

If the project is built with the `static` feature (default), you can use
[LeakyBucket] directly as long as you are inside a Tokio runtime, like so:

```rust
use leaky_bucket::LeakyBucket;
use std::{error::Error, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let rate_limiter = LeakyBucket::builder()
        .max(5)
        .tokens(5)
        .build()?;

    println!("Waiting for permit...");
    // should take about 5 seconds to acquire.
    rate_limiter.acquire(10).await?;
    println!("I made it!");
    Ok(())
}
```

Note that only one coordinator instance will be lazily created, and it's
associated with the runtime from within it was constructed. To use multiple
runtimes you must use an explicit coordinator as documented in the next
section.

### Example using explicit coordinator

Leaky buckets require coordination. By default, this will happen through a
static coordinator spawned through [tokio::spawn] at first use. If you want
to spawn the coordinator yourself, you can do the following with
[LeakyBuckets]:

```rust
use leaky_bucket::LeakyBuckets;
use std::{error::Error, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let mut buckets = LeakyBuckets::new();
    let coordinator = buckets.coordinate()?;

    // spawn the coordinate thread to refill the rate limiter.
    tokio::spawn(async move { coordinator.await.expect("coordinator errored") });

    let rate_limiter = buckets
        .rate_limiter()
        .max(5)
        .tokens(5)
        .build()?;

    println!("Waiting for permit...");
    // should take about 5 seconds to acquire.
    rate_limiter.acquire(10).await?;
    println!("I made it!");
    Ok(())
}
```

Note that since this coordinator uses timing facilities from tokio it has to
be spawned within a Tokio runtime with the [`time` feature] enabled.

[leaky bucket]: https://en.wikipedia.org/wiki/Leaky_bucket
[tokio::spawn]: https://docs.rs/tokio/0/tokio/fn.spawn.html
[LeakyBucket]: https://docs.rs/leaky-bucket/0/leaky_bucket/struct.LeakyBucket.html
[LeakyBuckets]: https://docs.rs/leaky-bucket/0/leaky_bucket/struct.LeakyBuckets.html
[`time` feature]: https://docs.rs/tokio/0.2.22/tokio/#feature-flags

License: MIT/Apache-2.0