loadwise answers one question: "given these nodes, which one should handle the next request?"
It ships 7 strategies, a health state machine, composable filters, and a pluggable state store — all in a synchronous, zero-allocation hot path. No async runtime, no tracing crate, no metrics dependency.
use ;
use RoundRobin;
let strategy = new;
let backends = ;
let ctx = default;
let idx = strategy.select.unwrap;
println!;
Why loadwise?
Most load balancers live inside a proxy. loadwise gives you the algorithm without the infrastructure — embed it in any Rust application, from an API gateway to an LLM router to a game server matchmaker.
- Zero-cost abstraction —
Strategy::selectreturns anOption<usize>, not a reference. No allocation on the hot path. - Protocol-agnostic — works with HTTP, gRPC, WebSocket, database connections, or anything you can put in a slice.
- Three opt-in traits —
Node(identity),Weighted(weight),LoadMetric(load score). Implement only what your strategy needs. - No opinion on I/O — no async runtime, no HTTP client, no health-check poller. You report events; loadwise manages state.
Strategies
| Strategy | Requires | Algorithm |
|---|---|---|
RoundRobin |
— | Atomic sequential cycling |
WeightedRoundRobin |
Weighted + Node |
Nginx smooth weighted round-robin |
Random |
— | Uniform random |
WeightedRandom |
Weighted |
Proportional random by weight |
LeastLoad |
LoadMetric |
Pick the node with lowest load_score() |
PowerOfTwoChoices |
LoadMetric |
Randomly sample 2, pick the less loaded — O(1) |
ConsistentHash |
Node |
Virtual-node hash ring with caching |
Compose strategies with WithFallback (generic, zero-cost) or FallbackChain (dynamic dispatch):
use ;
// Try least-load first; if no candidates remain after filtering, fall back to round-robin.
let strategy = new;
Health Tracking
A four-state machine with configurable thresholds:
┌─────────┐ failures ≥ ⌈t/2⌉ ┌──────────┐ failures ≥ t ┌───────────┐
│ Healthy │ ─────────────────→ │ Degraded │ ────────────────→ │ Unhealthy │
└─────────┘ └──────────┘ └───────────┘
↑ │ │
│ recovery_successes met │ 1 success │ 1 success
│ ↓ ↓
│ ┌─────────┐ ┌────────────┐
└──────────────────────────│ Healthy │←── recoveries ────│ Recovering │
└─────────┘ └────────────┘
use ;
let tracker = new;
tracker.report_failure;
tracker.report_failure;
tracker.report_failure;
assert_eq!;
tracker.report_success;
assert_eq!;
Filtering
Narrow candidates before selection — zero-allocation bitmask filters:
use ;
// Only route to healthy + recovering nodes
let filter = available;
// Combine filters with AND logic
let combined = new;
Observability
Bring your own metrics stack — loadwise provides a hook, not a dependency:
use MetricsCollector;
;
Crate Structure
loadwise/
├── loadwise-core Core traits, 7 strategies, health, filters, state store
├── loadwise Facade — re-exports core with optional feature flags
├── loadwise-store-redis Redis-backed StateStore (HASH-based, JSON-serialised)
└── loadwise-tower Tower Layer / Service adapter (planned)
| Crate | Description |
|---|---|
loadwise |
Facade — re-exports core, optional tower / redis features |
loadwise-core |
All logic: traits, strategies, health, filters, state store |
loadwise-store-redis |
Redis-backed StateStore via single HASH |
loadwise-tower |
Tower Layer / Service adapter (planned) |
Installation
[]
= "0.1"
MSRV: 1.85 (Rust edition 2024)
Design Principles
select()is synchronous — returns an index into the candidate slice. No futures, no allocation.- Interior mutability — strategies use
AtomicUsizeorMutexinternally; callers hold&self. - Fingerprint-based caching — stateful strategies (hash ring, WRR weights) detect candidate-set changes automatically via a hash of node IDs.
- Pluggable everything —
StateStorefor persistence,HealthPolicyfor state transitions,MetricsCollectorfor observability. Implement the trait, bring your own backend.
Contributing
Contributions are welcome! Please make sure cargo test passes and new public items have /// doc comments with examples.
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.