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§
- Adaptive
Controller - EWMA-feedback-driven limiter tuning (DW-089). Compiled once per
config generation from the
policies[].adaptiveblocks; shared viaArcfrom the dataplane generation.record_outcomeruns on the response path (after the upstream exchange resolves) andfactor_forruns on the request path (inside the rate-limit check) — both lock-free. Policies without an enabledadaptiveblock are absent from the map;factor_forreturns1.0for them (no adaptive tuning, the configured quotas apply as-is).