Expand description
The one clock port: monotonic time, sleeping, and the wall time since the epoch.
§One trait rather than one per module
The control plane and the session each had a Clock of their own, over different time
sources: the control plane’s read std::time::Instant and the session’s read tokio’s.
Under a deterministic simulator those disagree. tokio’s clock is virtual there and std’s
isn’t, so a control-plane wait whose sleeps advanced virtual time measured its deadline
on the host’s real time and never reached it. Sandbox already times the suspended window
on the plane’s clock rather than its own, so a window isn’t measured on one clock while
the polls run on another. One trait, with tokio’s clock in production, keeps that property
for everything that reads time. The trait is re-exported at control::Clock and at
session::Clock, the paths each half had.
§Why a trait rather than tokio::time::pause
The waits are driven by elapsed comparisons against a deadline and a stall grace, and a
test has to be able to say “now 300 seconds have passed” between two polls of a fake
control plane. A paused tokio clock can do that, but only for code that sleeps on tokio,
and it makes every test in a file share one global clock state. A Clock parameter
makes the dependency visible in the signature.
§Monotonic and wall time are separate readings
Clock::elapsed is monotonic, the same reasoning the Python client’s injectable
time.monotonic carried: the suspended window is a duration, and a wall clock that steps
backward would reopen a closed one. Clock::unix_now is the wall reading, for the values
that are dates rather than durations: a name record’s timestamp, an exec id, the cost
engine’s today. Deriving one from the other would make a stepped wall clock move a
deadline.
Traits§
- Clock
- Time, injectable so a wait or a refresh boundary is a test rather than a wait.