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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! The monotonic time source behind the coordination control loop.
//!
//! Production uses [`SystemClock`] — real wall time. Tests inject
//! `TestClock`, which only moves when the test moves it, so every
//! time-driven transition is deterministic regardless of CI scheduler
//! jitter: the coordinator forces a multi-thread runtime, so
//! `tokio::time::pause()` is unavailable and the timing would otherwise
//! track real time.
//!
//! The clock owns both halves of "when": reading the current instant
//! ([`Clock::now`]) *and* waiting for one ([`Clock::sleep_until`]). Every
//! deadline that drives a *protocol state transition* is drawn from it —
//! lease expiry and the starvation self-fence, the heartbeat/reconcile/
//! replan cadence, the `rebalance_delay` grace window, the drain deadline,
//! and the renewal cadence gate — so a frozen clock cannot freeze half the
//! protocol and let the other half race.
//!
//! Deliberately *not* on the clock, because each bounds real I/O rather
//! than protocol time: `op_timeout` (`store::metered`), the command reply
//! budget (`coordinator`), the startup and re-watch retry backoffs
//! (`task`), and `MemoryStore`'s sweeper cadence — the sweeper's *cadence*
//! is real, but what it expires is judged against the clock. So a frozen
//! clock stops the protocol; it does not stop the crate from using real
//! time where real time is the thing being bounded. Commands are served on
//! a clock-independent select arm, which is what lets a test drive a
//! coordinator whose clock is not moving.
//!
//! # Advancing a frozen clock
//!
//! Time only moves on `TestClock::advance`, and what is safe to advance
//! by depends on whether the worker under test can still renew:
//!
//! - **Advance to expire.** Jumping past a whole lease is deterministic
//! *only* when the target cannot renew anyway — a crashed runtime, a
//! kill-switch store, an injected fault. Nothing is racing the jump.
//! - **Advance to settle.** For "hold steady and assert nothing changes"
//! windows the worker is alive and must win its renewals, so step in
//! increments no larger than `renew_interval` and let the task run
//! between them. `TestClock::advance_stepped` does exactly that; a
//! single large jump here would make a lease expiry and the renewal that
//! prevents it come due at the same instant, which is a real race.
use Future;
use Pin;
// Only `TestClock` needs `Duration`; the trait and `SystemClock` do not.
use Duration;
use Instant;
/// A future that resolves when a [`Clock`] reaches some instant.
///
/// Boxed and `'static`: implementations must not borrow the clock, so a
/// caller can hold the future across a `select!` arm whose body needs
/// `&mut self`.
///
/// One is drawn per timer arm per `select!` entry, so the rate is the
/// control loop's wakeup rate — not a fixed cadence. A commit wakes the
/// loop (`Command::Commit` is sent unconditionally), and the pipeline
/// controller tightens to `FAST_COMMIT_POLL` while chasing a fast-commit
/// partition, so the loop can iterate in the low milliseconds. Still off
/// the per-record path, and every such iteration already `Box::pin`s its
/// handler — the same trade, at the same rate.
pub type Sleep = ;
/// A monotonic clock. Returns [`tokio::time::Instant`] so the value slots
/// straight into the existing lease/deadline fields without a type change.
///
/// `Debug` is required because [`MemoryStore`](crate::store::memory::MemoryStore)
/// derives it and holds a clock.
/// Real wall time — the production clock.
;
/// A clock that only moves when a test moves it. See the [module
/// docs](self) for the two advancing patterns.
///
/// Behind the `testing` feature and `#[doc(hidden)]`: it has to be `pub`
/// for this crate's `tests/` binaries, which are external crates and
/// cannot see `#[cfg(test)]` items, but it must not reach a consumer — a
/// `TestClock` wired into production would stop the control loop dead.
/// Off by default and never enabled by the `spate` facade, the same shape as
/// `spate-s3`'s `testing` feature.