1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Stateful revision convergence: making replicas serve desired state without
//! restarting them (#142).
//!
//! A stateful deployment's desired state is a chain of immutable revisions in the
//! control plane (ADR 0027, [`crate::desired_state`]). This module is how a
//! running replica gets from "a new revision was published" to "requests are
//! being served from it", and — just as importantly — what happens when it
//! cannot.
//!
//! # The shape
//!
//! | Module | Answers |
//! | --- | --- |
//! | [`settings`] | how often to look, how long divergence may last, how to pace retries |
//! | [`compile`] | how a hydrated revision becomes a whole runtime snapshot, and every way that fails |
//! | [`credentials`] | how a revision's provider credentials become the pools a provider call leases from |
//! | [`policy`] | which published document governs each projected namespace |
//! | [`reconciler`] | the loop: observe, hydrate, compile, publish, report, back off |
//! | [`status`] | what the replica reports: desired, loaded, active, lag, last refusal |
//! | [`backoff`] | bounded exponential retry pacing |
//! | [`lkg`] | the signed last-known-good cache a replica may cold-boot from |
//!
//! # Four properties, and where each is enforced
//!
//! **One snapshot per request.** Convergence publishes by replacing an
//! [`ArcSwap`](arc_swap::ArcSwap)ped snapshot, and a request loads that pointer
//! once and holds the `Arc` for its lifetime (see [`crate::state`]). A buffered
//! request that started under revision *N* finishes under *N*, and a stream that
//! started under *N* relays to completion under *N*, even though *N+1* became
//! active in between. Nothing in this module can change that, because nothing in
//! it can reach into a published snapshot — publication is a whole-value store.
//!
//! **A refused candidate changes nothing.** [`compile`] builds a candidate from a
//! hydrated revision without ever being given the running snapshot, so fetch,
//! hydration, validation, compilation, and secret-resolution failures cannot
//! half-apply. The reconciler's failure path records a reason and backs off; it
//! has no rollback to perform, because there was no partial application.
//!
//! **Polling is correctness; ordinary notification is latency.** A Postgres
//! notification delivered while a replica reconnects is lost, so convergence
//! never depends on one: [`reconciler::ChangeSignal`] only shortens the wait
//! between polls for durable desired-state changes. Its explicit force-refresh
//! form also re-runs the candidate path for runtime inputs, such as secret
//! lifecycle state, that do not create a new revision.
//!
//! **An outage degrades to staleness, not unavailability.** A replica that cannot
//! reach the control plane keeps serving its active snapshot, retries on a bounded
//! backoff, and reports its lag. A replica that *boots* during an outage may
//! restore the signed [`lkg`] cache, which is authenticated before it is
//! interpreted and re-verified through the domain's integrity checks after.
//!
//! **A published policy is admitted before it is served.** A candidate carries
//! the limits [`policy`] attached to it, and the sink is asked
//! ([`reconciler::SnapshotSink::admit`]) whether this replica's backends and its
//! outstanding holds permit them *before* the snapshot is published
//! ([`crate::policy::PolicyRuntime::plan`]). A refusal is an ordinary rejection
//! with its own reason, and the replica keeps both the configuration and the
//! policy it already had.
//!
//! # Serving boundary
//!
//! `serve` owns the bootstrap snapshot and the reconciler owns every projected
//! replacement. A stateful bootstrap is intentionally keyless and therefore
//! cannot authenticate traffic; only a candidate with a complete projected
//! inbound-key set may become active. A control-plane outage leaves the active
//! immutable snapshot in place, while a cold boot without a valid projection or
//! signed last-known-good cache remains fail-closed until recovery.
// The convergence facade. `allow(unused_imports)` for the same reason the
// desired-state facade carries it: this is a binary crate, and a re-export that
// nothing in the tree names yet is still part of the contract the projection
// slices build against.
pub use ;
pub use ;
pub use ;
pub use ;
pub use PolicyProjection;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use TenancyProjection;