Expand description
Weighted canary / A-B traffic splitting middleware.
CanaryLayer implements Middleware and distributes incoming requests
across a set of backends according to configurable weights, using the same
smooth weighted round-robin (SWRR) algorithm nginx uses: each backend has
a current_weight that accumulates its configured weight every selection
and is decremented by the total weight whenever it’s picked. That spreads
high-weight backends evenly through the sequence instead of bursting them
consecutively — weights 5, 1, 1 select roughly A A B A C A A (repeating),
never five As in a row, unlike a flat pre-expanded rotation list would.
Backends are contacted over plain HTTP/1.1, or over TLS when the backend
URL uses an https://, h2s://, or grpcs:// scheme (requires the
http-client or http2 feature — both pull in rustls). If a backend is
unavailable the next one in the fallback order is tried; after exhausting
all backends the middleware returns 502 Bad Gateway.
A group’s members can also come from a crate::service_discovery::BackendPool
instead of a fixed URL — see WeightedPool / CanaryLayer::add_pool —
so e.g. “10% of traffic to the canary group” keeps working as pods in that
group come and go, without touching the weight itself.
Weights can be replaced at runtime with CanaryLayer::update — clone the
layer before wrapping it to keep a handle for later:
use rust_web_server::app::App;
use rust_web_server::core::New;
use rust_web_server::canary::{CanaryLayer, WeightedBackend};
use rust_web_server::middleware::WithMiddleware;
// 75 % of traffic → stable, 25 % → canary
let layer = CanaryLayer::new(vec![
WeightedBackend::new("http://stable:8080", 3),
WeightedBackend::new("http://canary:8080", 1),
])
.path_prefix("/api");
let handle = layer.clone(); // keep this — `layer` moves into `.wrap(...)`
let app = WithMiddleware::new(App::new()).wrap(layer);
// Later — e.g. from an admin endpoint or a rollout script — shift more
// traffic to canary without restarting the process:
handle.update(
vec![
WeightedBackend::new("http://stable:8080", 1),
WeightedBackend::new("http://canary:8080", 1),
],
vec![],
);Structs§
- Canary
Layer - Weighted traffic-splitting proxy middleware.
- Weighted
Backend - A single fixed backend URL together with a relative traffic weight.
- Weighted
Pool - A dynamically-discovered group of backends (a
BackendPool) together with a relative traffic weight for the group as a whole. Which specific pool member answers a given request is a plain round-robin overpool.backends()at the time of selection — the weight only controls how often this group is picked relative to other groups/backends, not which member within it.