Skip to content

Deprecate or implement internal rate limiting? #190

@udoprog

Description

@udoprog

#182 was fixed, but I didn't implement rate limiting using burst windows. As per the comment in #184, I raised the question whether this project should provide a built-in rate limiter at all or if we should encourage the user to use an external project like leaky-bucket (full disclosure: my project).

The following is an example of how an external rate limiter is used for anyone who is curious. Unfortunately this hides a lot of utility functions of Sender (like send_cap_req) and it's not straight forward to make async functions like acquire below pluggable. async functions are not supported in traits, nor do we have existential types yet so the anonymous future can be named.

The benefit however is that the rate limiter is an async function that can be await:ed at any point. You have full control over its configuration, use, and implementation. Rate limiting happens before the send is buffered which makes sure that the rest of your application is back pressured when necessary.

use anyhow::Result;
use irc::{Message, Sender};
use leaky_bucket::LeakyBucket;

struct RateLimitedSender {
    sender: irc::Sender,
    rate_limiter: LeakyBucket,
}

impl RateLimitedSender {
    pub fn new(sender: Sender) -> Result<Self> {
        Ok(Self {
            sender,
            leaky_bucket: LeakyBucket::builder()
                .max(100)
                .refill_interval(Duration::from_secs(10))
                .refill_amount(100)
                .build()?,
        })
    }

    pub async fn send(m: impl Into<Message>) -> Result<()> {
        self.rate_limiter.acquire(1).await?;
        self.sender.send(m);
        Ok(())
    }
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions