#cloudflare-workers #rate-limiting #worker #general #rules

worker-ratelimit

General purpose rate limiting library for Cloudflare Workers

3 releases (breaking)

0.3.0 Apr 4, 2024
0.2.0 Mar 28, 2024
0.1.0 Mar 16, 2024

#594 in Network programming

Download history 124/week @ 2024-03-11 28/week @ 2024-03-18 137/week @ 2024-03-25 134/week @ 2024-04-01 5/week @ 2024-04-08

362 downloads per month

MIT/Apache

10KB
187 lines

worker-ratelimit crates.io docs.rs

This is a general purpose rate limiting library for Cloudflare Workers. It builds on top of Cloudflare Workers KV for storage.

This library is meant to compile to WebAssembly and execute on Cloudflare's serverless plattform. Please note, this is not an official Cloudflare project and implements rate-limiting non-atomically, on best-effort basis, meaning it may fail to count some actions happening in quick succession. Users may be able to go slightly above the configured limits, but once they are reached the limits are effective. Ratelimiting is implemented with a BTree-based sliding-window algorithm.

This library is meant to work with features available on free-tier. For more serious use definitely also consider the "Security > WAF > Rate limiting rules" settings.

Usage

Configure a RateLimiter struct containing your rules.

use worker_ratelimit::RateLimiter;

pub fn setup_ratelimiter() -> RateLimiter {
    // Use the `ratelimit/<key>` namespace within the KV store
    let mut limits = RateLimiter::new("ratelimit");
    // Allow no more than 2 actions within 5 seconds
    limits.add_limit(Duration::from_secs(5), 2);
    // Allow no more than 10 actions within 1 minute
    limits.add_limit(Duration::from_secs(60), 10);
    // Allow no more than 50 actions within 1 hour
    limits.add_limit(Duration::from_secs(3600), 50);
    limits
}

Interact with your KV-backed ratelimits like this:

let ratelimits = setup_ratelimiter();

// Get the request ip address
let ip_addr = req.headers().get("x-real-ip")?.unwrap_or_else(String::new);

// Check the rate-limit thresholds (also providing the current time)
let Permit::Allow(ticket) = ratelimits.check_kv(&kv, &ip_addr, &Date::now()).await? else {
    return Response::error("Rate limit exceeded", 429);
};

/* Perform the action */
do_something().await?;

// Increase the ratelimit counter (if needed)
if let Some(ticket) = ticket {
    ticket.redeem(&kv).await?;
}

License

MIT OR Apache-2.0

Dependencies

~1.4–5MB
~103K SLoC