Module adaptive

Module adaptive 

Source
Expand description

Adaptive + origin-driven rate-limit tuning (DW-089).

An AdaptiveController holds per-policy atomic EWMA state for the upstream error rate and latency, plus a current adaptive factor that scales a policy’s rate-limit quotas at check time. The controller is compiled once per config generation from the policies[].adaptive blocks (only policies with adaptive.enabled contribute state); it is shared via Arc from the dataplane generation and updated on the response path (record_outcome), then read on the request path (factor_for) — both lock-free, the same atomic-EWMA pattern as the balancer’s PeakEwmaTracker (in dataplane::balance).

§Factor logic

The adaptive factor is bounded [min_factor, max_factor] (never 0, never unbounded). When the upstream is stressed (error EWMA above error_threshold OR latency EWMA above latency_threshold_ms) the factor DECREASES toward min_factor (tighten — each request “costs more” against the GCRA bucket, so the effective rate drops). When the upstream is healthy the factor INCREASES toward max_factor (relax — each request “costs less”, so the effective rate rises). Tightening is faster than relaxing (asymmetric: TIGHTEN_RATE < 1.0 multiplies the factor down by ~5% per stressed update, RELAX_RATE > 1.0 multiplies it up by ~1% per healthy update), so the gateway errs toward protecting upstreams.

§Origin signals

When retry_after is in origin_signals and the upstream response carries a Retry-After header, record_outcome sets a backoff deadline (now + retry_after_duration) and drops the factor to min_factor immediately. While within the backoff window, factor_for returns min_factor regardless of the EWMA state; once the window elapses the EWMA-driven factor resumes.

§Atomic f64 storage

Error EWMA, latency EWMA, the factor, and the backoff deadline are stored as AtomicU64 holding the bits of an f64 (f64::to_bits / f64::from_bits), exactly like the balancer’s PeakEwmaTracker cost_ns. The stamp is nanoseconds since the Unix epoch (the same system_now_ns clock the balancer uses). All loads/stores are Ordering::Relaxed: the values are advisory (a stale factor merely tightens or relaxes one request early), so the relaxed ordering is correct and the hot path stays lock-free.

Structs§

AdaptiveController
EWMA-feedback-driven limiter tuning (DW-089). Compiled once per config generation from the policies[].adaptive blocks; shared via Arc from the dataplane generation. record_outcome runs on the response path (after the upstream exchange resolves) and factor_for runs on the request path (inside the rate-limit check) — both lock-free. Policies without an enabled adaptive block are absent from the map; factor_for returns 1.0 for them (no adaptive tuning, the configured quotas apply as-is).