Skip to main content

Crate tower_resilience_router

Crate tower_resilience_router 

Source
Expand description

Weighted traffic routing for Tower services.

This crate provides a WeightedRouter service that distributes requests across multiple backend services based on configured weights. It is designed for canary deployments, progressive rollouts, and controlled traffic splitting.

§Overview

Unlike other tower-resilience patterns which wrap a single service and modify its behavior, WeightedRouter selects among multiple services. It is a standalone Service, not a Layer.

All backend services must have the same Request, Response, and Error types. For canary deployments (same service, different version), this is the natural case.

§Selection Strategies

  • Deterministic (default): Uses an atomic counter for predictable, repeatable distribution. With weights [90, 10], every cycle of 100 requests sends exactly 90 to the first backend and 10 to the second.

  • Random: Each request independently selects a backend with probability proportional to its weight. Better for high-volume statistical distribution, but may show variance at low traffic.

§Readiness

poll_ready checks that all backends are ready. This is the simplest and most predictable contract. If a backend is slow or failing, pair it with a circuit breaker so that readiness resolves quickly (open circuit = immediate ready or error).

§Example

Because all backends must be the same type S, use BoxService when constructing from different closures:

use tower::Service;
use tower::util::BoxService;
use tower_resilience_router::WeightedRouter;

let svc_v1: BoxService<String, String, std::io::Error> =
    BoxService::new(tower::service_fn(|req: String| async move {
        Ok(format!("v1: {}", req))
    }));
let svc_v2: BoxService<String, String, std::io::Error> =
    BoxService::new(tower::service_fn(|req: String| async move {
        Ok(format!("v2: {}", req))
    }));

let mut router = WeightedRouter::builder()
    .route(svc_v1, 90)
    .route(svc_v2, 10)
    .build();

§Composability

The natural composition pattern puts resilience middleware inside each backend:

use tower::Layer;
use tower_resilience_router::WeightedRouter;

// Each backend gets its own circuit breaker
// let cb = CircuitBreakerLayer::standard().build();
// let router = WeightedRouter::builder()
//     .route(cb.layer(svc_v1), 90)
//     .route(cb.layer(svc_v2), 10)
//     .build();

Re-exports§

pub use config::WeightedRouterBuilder;
pub use error::WeightedRouterError;
pub use events::RouterEvent;
pub use selection::SelectionStrategy;

Modules§

config
Configuration and builder types for the weighted router. Configuration for the weighted router.
error
Error types for routing failures. Error types for the weighted router.
events
Event types emitted when requests are routed. Event types for the weighted router.
selection
Backend selection strategies (deterministic, random). Selection strategies for weighted routing.

Structs§

WeightedRouter
A service that routes requests to one of several backends based on weights.