Rate Limiting in Rust
Here’s the translation of the Go rate limiting example to Rust, formatted in Markdown for Hugo:
use std::time::{Duration, Instant};
use std::thread;
use std::sync::mpsc;
fn main() {
// First we'll look at basic rate limiting. Suppose
// we want to limit our handling of incoming requests.
// We'll serve these requests off a channel of the
// same name.
let (tx, rx) = mpsc::channel();
for i in 1..=5 {
tx.send(i).unwrap();
}
drop(tx);
// This `limiter` will receive a value every 200 milliseconds.
// This is the regulator in our rate limiting scheme.
let limiter = std::iter::repeat_with(|| {
thread::sleep(Duration::from_millis(200));
Instant::now()
});
// By blocking on a receive from the `limiter` iterator
// before serving each request, we limit ourselves to
// 1 request every 200 milliseconds.
for (req, _) in rx.iter().zip(limiter) {
println!("request {} {:?}", req, Instant::now());
}
// We may want to allow short bursts of requests in
// our rate limiting scheme while preserving the
// overall rate limit. We can accomplish this by
// buffering our limiter channel. This `bursty_limiter`
// channel will allow bursts of up to 3 events.
let (bursty_tx, bursty_rx) = mpsc::sync_channel(3);
// Fill up the channel to represent allowed bursting.
for _ in 0..3 {
bursty_tx.send(Instant::now()).unwrap();
}
// Every 200 milliseconds we'll try to add a new
// value to `bursty_tx`, up to its limit of 3.
thread::spawn(move || {
loop {
thread::sleep(Duration::from_millis(200));
bursty_tx.send(Instant::now()).unwrap();
}
});
// Now simulate 5 more incoming requests. The first
// 3 of these will benefit from the burst capability
// of `bursty_rx`.
let (bursty_req_tx, bursty_req_rx) = mpsc::channel();
for i in 1..=5 {
bursty_req_tx.send(i).unwrap();
}
drop(bursty_req_tx);
for req in bursty_req_rx {
bursty_rx.recv().unwrap();
println!("request {} {:?}", req, Instant::now());
}
}
This Rust code demonstrates rate limiting using channels and threads. Here’s a breakdown of the implementation:
We first create a basic rate limiter using a channel and an iterator that produces values every 200 milliseconds.
We then implement a bursty rate limiter using a synchronous channel with a capacity of 3, allowing short bursts of requests while maintaining the overall rate limit.
The
mpsc::channel()
andmpsc::sync_channel()
functions are used to create channels for communication between threads.We use
thread::sleep()
to simulate time delays andInstant::now()
to get the current time for logging.The
thread::spawn()
function is used to create a new thread that continuously adds values to the bursty limiter channel.
Running this program will show the first batch of requests handled once every ~200 milliseconds as desired. For the second batch of requests, we’ll see the first 3 served immediately due to the burstable rate limiting, then the remaining 2 with ~200ms delays each.
This Rust implementation provides similar functionality to the original example, demonstrating rate limiting concepts in a language with different concurrency primitives.