Skip to main content

Crate request_shadow

Crate request_shadow 

Source
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 over reqwest::Client for 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 a tokio::join!, returns a ShadowOutcome.
  • 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 Backend in 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.