pub struct Upstream {
pub name: String,
pub addresses: Vec<AddressSpec>,
pub tls: Option<UpstreamTls>,
pub lb_algorithm: LbAlgorithm,
pub hash: Option<HashConfig>,
pub health: HealthConfig,
pub resolve_interval_ms: u64,
pub request_timeout_ms: u64,
pub max_retries: u64,
pub overall_timeout_ms: u64,
pub circuit_breaker: CircuitBreaker,
pub outlier_detection: OutlierDetection,
}Expand description
A named upstream the fast-path server forwards a matched request to (ADR 000013 / 000017).
One or more addresses (host:port, no scheme) are the upstream’s instances; the fast path
balances across the healthy ones per lb_algorithm. The forward leg is plain HTTP/1.1 unless
[upstream.tls] is declared, which re-encrypts with rustls and lets ALPN negotiate h2 /
http/1.1 (ADR 000042). Every upstream carries an active-health-check policy (health) —
required, because instances start pessimistic (unhealthy) and only a passing probe puts one
into rotation (ADR 000017).
Fields§
§name: String§addresses: Vec<AddressSpec>Each backend instance’s host:port (no scheme — [upstream.tls] decides the scheme for
the whole upstream, ADR 000042). Each entry is either a bare string ("127.0.0.1:9000",
weight 1) or a weighted inline table ({ address = "...", weight = N }) for heterogeneous
instances (ADR 000035). Must be non-empty (validated at build). The two forms mix in one
list; a bare string and an explicit weight = 1 are equivalent (same content hash).
tls: Option<UpstreamTls>[upstream.tls] (ADR 000042): when present, the forward leg to every instance re-encrypts
with TLS and ALPN negotiates the protocol (h2 preferred, http/1.1 fallback). Absent = plain
HTTP/1.1 (the pre-000042 behaviour). There is no insecure/verify-off escape hatch —
verification failure keeps the instance out of rotation (fail-closed).
lb_algorithm: LbAlgorithmPer-upstream load-balancing algorithm (ADR 000035): round_robin (default), least_request
(power-of-two-choices over per-instance active requests), or maglev (consistent hashing for
session affinity). The chosen algorithm selects an instance from the healthy set; default
round_robin keeps the pre-000035 behaviour with no per-request cost change.
hash: Option<HashConfig>Maglev hash config (ADR 000035), [upstream.hash]. Required iff lb_algorithm = "maglev"
(a maglev upstream needs a hash key; any other algorithm must not set it). Absent otherwise.
health: HealthConfigActive-health-check policy for this upstream’s instances (ADR 000017).
resolve_interval_ms: u64How often (ms) hostname addresses are re-resolved and the endpoint set refreshed — the
standard periodic-DNS endpoint-discovery technique (the shape of nginx resolve / Envoy
STRICT_DNS): each A/AAAA record becomes a load-balancing endpoint with its own health;
a vanished record is dropped, a new one starts pessimistic (ADR 000017); a failed
resolution keeps the last-known-good set. Interval-based (getaddrinfo carries no TTL) —
pick a value at or below your DNS TTL. 0 disables (the default): hostnames still
resolve per connect, but the endpoint set stays as declared.
request_timeout_ms: u64End-to-end timeout (ms) for forwarding a request to this upstream (ADR 000019 / review
f000005 P2#4). Bounds time-to-response-headers; once headers arrive the body streams without
a deadline, so streaming responses are unaffected. Exceeding it fails closed with 504.
Default 30000; 0 disables the timeout (for long-poll / streaming upstreams).
max_retries: u64Maximum times the fast path re-sends this upstream’s request to a DIFFERENT healthy instance
after a retryable failure (ADR 000023). A timeout is retried only for an idempotent method
(the upstream may have acted); a connect failure — the upstream never received the request —
is retried for any method. Only bodyless requests are retried (the opaque streamed body,
ADR 000013, can’t be replayed). Default 1; 0 disables retry.
overall_timeout_ms: u64Overall request timeout (ms) bounding the WHOLE transaction — every attempt PLUS the backoff
between them (ADR 000031) — whereas request_timeout_ms bounds a single attempt (per-try).
This is the end-to-end deadline across retries; exceeding it fails closed 504
(x-plecto-fault: request-timeout, distinct from the per-try upstream-timeout). Should be
>= request_timeout_ms; the runtime applies the tighter of the two regardless. Default 0 =
no overall bound (only the per-try timeout applies — the pre-000031 behaviour).
circuit_breaker: CircuitBreakerPer-upstream circuit breaker (ADR 000028): bounds the load the fast path puts on this
upstream. Distinct from health — health ejects failing instances, this caps concurrent
work on healthy ones so a saturated backend sheds load fast instead of queueing unbounded.
Absent = unlimited (the default).
outlier_detection: OutlierDetectionPer-upstream outlier detection (ADR 000032): eject an instance from rotation when it
MISBEHAVES on live traffic (gateway-class 5xx), a third resilience axis distinct from active
health (“is it reachable?”) and the circuit breaker (“is it saturated?”). Absent / threshold
0 = disabled (the default).
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Upstream
impl<'de> Deserialize<'de> for Upstream
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for Upstream
impl JsonSchema for Upstream
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for Upstream
impl RefUnwindSafe for Upstream
impl Send for Upstream
impl Sync for Upstream
impl Unpin for Upstream
impl UnsafeUnpin for Upstream
impl UnwindSafe for Upstream
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more