Rust · no network plumbing
Ferryman is a load balancer in Rust, isolated down to the part that actually decides: round-robin, weighted round-robin, least-connections, and seeded random, plus health tracking that skips a backend the instant it goes down. Try it below.
toggle a backend unhealthy and watch requests reroute live
The same four strategies, running underneath, with health and connection state kept per backend.
A cursor walks the backend list in order, wrapping around, skipping anything unhealthy along the way.
Smooth weighted selection accumulates a current weight per backend each pick and always takes the highest.
Picks the healthy backend with the fewest active connections right now, ties broken by id.
A tiny xorshift PRNG picks uniformly among healthy backends, reproducible from a fixed seed.
Marking a backend down removes it from every strategy immediately, marking it up brings it straight back.
If every backend is unhealthy, the balancer returns a typed error instead of crashing or hanging.
The demo binary prints the same decisions the crate makes. Over one full cycle of weighted round-robin, each backend is picked exactly as many times as its weight, and no more.
A full load balancer is mostly network plumbing, with the selection logic buried inside it. Ferryman keeps only that logic, so it is deterministic and testable on its own.
Full proxies: they terminate connections, parse protocols, and manage sockets, with the balancing algorithm one part buried inside all of it. Powerful, and not something you can unit-test in isolation.
A managed black box. You configure a strategy and trust it. There is no small readable implementation to study or assert against.
The request-distribution strategies and health tracking, and nothing else. Given backends and their state, it returns which one gets the next request, deterministically, with every path covered by tests.
The same routing logic ships three ways. Call it directly, run the demo binary, or read the tests that pin every strategy down.
Build a Balancer from a set of Backends and a Strategy, then call next(). Use acquire and release to track connections, and mark_down and mark_up for health.
cargo run -- demo with an algo, a backend count, a request count, and a seed. It prints which backend each request went to, plus a final tally.
cargo test covers round-robin ordering, weighted distribution over a full cycle, least-connections under acquire and release, health toggling, the all-unhealthy and empty-pool error paths, and seeded reproducibility.
# route 12 requests round-robin across 3 backends cargo run -- demo --algo round-robin --backends 3 --requests 12 # seeded random is reproducible run to run cargo run -- demo --algo random --backends 3 --requests 15 --seed 42