Expand description
§request-shadow
Async request mirroring with sampling, divergence detection, and structured response diffs. The SRE primitive for migrations: send the same request to the production service AND a candidate, compare the responses, return the production one to the client while you collect divergence telemetry.
§Why a small crate
Every service-mesh has a knob for this — Linkerd shadowing, Istio mirror, AWS App Mesh. Those are great when you own the mesh. They’re useless when the migration is in-process (binary library swap, codec change, JSON-vs- protobuf swap, ORM cutover). This crate gives you the same shape as a 30-line Tokio task:
let primary = Arc::new(Mock(ResponseRecord::ok(b"prod".to_vec())));
let shadow = Arc::new(Mock(ResponseRecord::ok(b"prod".to_vec())));
let shadower = Shadower::new(primary, shadow, ShadowConfig::full_sample());
let outcome = shadower.call(b"hello").await?;
assert!(outcome.primary.ok);
assert!(outcome.divergence.is_none()); // bytes match§Pieces
Backend— the async-trait abstraction the shadower calls. Implement it overreqwest::Clientfor HTTP, or any in-process call.ResponseRecord— what a backend returns: status code, headers, body.ShadowConfig— sampling rate (sticky over a key hash), timeout for the shadow leg, fields to ignore in the diff.Shadower— picks whether to mirror based on the sampling key, fires both calls in atokio::join!, returns aShadowOutcome.Divergence— structured diff: status / headers / body each get their own bool + summary.DivergenceLog— bounded ring buffer so the shadower can hand operators the last N divergences without unbounded memory growth.
§Composes with
- reliability-toolkit-rs
— wrap the shadow
Backendin a [CircuitBreaker] so a flaky candidate never bleeds into the primary path. - slo-budget-tracker — record every divergence against an SLO so you can answer “is the candidate good enough to promote?”
Re-exports§
pub use backend::Backend;pub use backend::ResponseRecord;pub use config::IgnoreField;pub use config::ShadowConfig;pub use divergence::Divergence;pub use error::ShadowError;pub use log::DivergenceLog;pub use shadower::ShadowOutcome;pub use shadower::Shadower;
Modules§
- backend
- The async backend abstraction.
- config
- Shadow configuration.
- divergence
- Structured response diff.
- error
- Crate-wide error type.
- log
- Bounded ring buffer for divergence records.
- shadower
Shadower— the main type. Fires primary + shadow legs concurrently and returns the primary response plus an optional divergence.