Batcher (Rust)
Topics: generics, timers, channels, graceful shutdown
Problem
Implement a generic Batcher<T> that coalesces individual items into batches, flushing when
either a size threshold is reached or a time window elapses. This is the batch-processing /
traffic-shaping pattern a gateway uses to amortize expensive downstream calls (bulk DB writes,
batched API requests, log shipping).
pub struct Batcher<T> { /* … */ }
impl<T: Send + 'static> Batcher<T> {
pub fn new<F>(max_size: usize, max_wait: Duration, flush: F) -> Self
where F: Fn(Vec<T>) + Send + 'static;
pub fn add(&self, item: T);
pub fn close(&mut self);
}
new starts a background worker. flush receives each completed batch.
add appends an item to the current batch.
- Flush when the batch reaches
max_size, or when max_wait elapses since the first item
of the current batch — whichever comes first.
close flushes any pending items, stops the worker, and returns only once it has exited.
flush must never be called with an empty batch.
Key concepts
- Single owner thread: one worker owns the batch
Vec, so no mutex is needed — it loops over an
mpsc channel with recv_timeout.
- Deadline on first item: set the deadline when a batch goes from empty → 1 item, so the window
measures "time since the batch started." With no batch, block on
recv (no timer).
recv_timeout as select: Ok = new item, Timeout = window elapsed → flush, Disconnected
= the sender was dropped (close) → flush the tail and exit.
- Graceful close: dropping the
Sender disconnects the worker; join makes close block until
the final flush is done.
Grading
Your solution.rs is compiled together with a trusted tests.rs (which include!s it) using
rustc --test. Only solution.rs is yours to edit.
Sign in to submit your solution.