Ferryman logo

Rust · no network plumbing

Which backend gets
the next request.

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.

Strategy

toggle a backend unhealthy and watch requests reroute live

How to use this playground
Pick a strategy from the dropdown, then hit Send request or Send 10 and watch each request light up the backend it routed to. Click Mark unhealthy on any backend to drop it from rotation and see traffic reroute instantly; mark it healthy to bring it back. Reset starts the run over. It is the same routing logic as the Rust crate, ported to JavaScript.

How it works

The same four strategies, running underneath, with health and connection state kept per backend.

1

Round-robin

A cursor walks the backend list in order, wrapping around, skipping anything unhealthy along the way.

2

Weighted round-robin

Smooth weighted selection accumulates a current weight per backend each pick and always takes the highest.

3

Least-connections

Picks the healthy backend with the fewest active connections right now, ties broken by id.

4

Random, seeded

A tiny xorshift PRNG picks uniformly among healthy backends, reproducible from a fixed seed.

5

Health tracking

Marking a backend down removes it from every strategy immediately, marking it up brings it straight back.

6

No panics

If every backend is unhealthy, the balancer returns a typed error instead of crashing or hanging.

Weight in, exactly that share out.

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.

$ cargo run -- demo --algo weighted-round-robin --backends 4 --requests 10
strategy: weighted-round-robin
backends: 4

request 1 -> backend 3
request 2 -> backend 2
request 3 -> backend 1
request 4 -> backend 3
request 5 -> backend 0
request 6 -> backend 2
request 7 -> backend 3
request 8 -> backend 1
request 9 -> backend 2
request 10 -> backend 3

tally:
  backend 0 : 1
  backend 1 : 2
  backend 2 : 3
  backend 3 : 4

Just the part that decides.

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.

nginx, HAProxy, Envoy

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.

Cloud load balancers

A managed black box. You configure a strategy and trust it. There is no small readable implementation to study or assert against.

Ferryman

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.

A library first, a CLI to watch it.

The same routing logic ships three ways. Call it directly, run the demo binary, or read the tests that pin every strategy down.

Library

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.

CLI

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.

Tests

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