Skip to content

The engine reads the clock itself in nineteen places, and three crates keep their own copy of the wall clock #6484

Description

@macanderson

The problem

stella-core had a Clock port that almost nothing used, and the deadline arithmetic read std::time::Instant::now() itself in nineteen places. #6486 fixed that half: every instant, wait and timeout in the engine now goes through retry::Sleeper (now() joined sleep and jitter), and scripts/core-no-io-baseline.txt is empty. This issue is the other half.

The real time sources are copied. A Unix-epoch wall clock lives three times (stella-cli/src/runtime.rs WallClock, stella-runtime/src/wrapper/stamp.rs HostClock, stella-serve/src/remote.rs WallClock), a Tokio sleeper twice (stella-cli/src/runtime.rs, stella-serve/src/remote.rs), and stella-fleet/src/monitor.rs keeps a Sleeper trait of its own with a third TokioSleeper. The two test doubles (NoopSleeper / NoSleep, and a TokioSleeper on the paused clock) are written about thirty times across stella-core, stella-engine and their tests/ directories. stella-serve may not depend on stella-runtime or stella-cli, and stella-core may not link the Tokio timer, so the copies have no shared home today.

What done looks like

  • one real TokioSleeper, WallClock and MonotonicClock, in one crate that stella-cli, stella-runtime, stella-serve and stella-fleet all use; the copies are deleted, and stella-fleet's own Sleeper trait is gone
  • one PausedSleeper and one NoopSleeper test double, shipped behind a test-util feature; the per-file copies in stella-core and stella-engine are deleted
  • a witness test that reads the tree and fails on any impl Sleeper for or wall/monotonic clock struct outside that crate, with the doubles that stay on purpose named and their reasons given
  • an ADR records the design fix(stella-core): read every instant, wait and timeout through the Sleeper port #6486 merged (why now sits on Sleeper, why the reading is an Instant) and where the real sources and the doubles live
  • CI is green on the PR

Constraints already found

  • stella-core may not link tokio/time (make core-no-io), so a faithful sleeper double cannot live there; the crate that holds the real sleeper holds the doubles, and stella-core takes it as a dev-dependency (cargo allows the cycle; tokio / tokio-test is the shape)
  • a sleeper that returns at once makes every engine timeout fire the moment a provider future waits on another task (fix(stella-core): read every instant, wait and timeout through the Sleeper port #6486's finding), so the shared doubles are two: one on tokio's paused clock for timed turns, one that never waits for untimed ones
  • scripts/check-core-no-io.py strips only #[cfg(test)], so nothing feature-gated may read a clock inside stella-core

Pillar

Maintainability (one time source, two doubles, one place to fix either) and reliability (the paused double keeps timeouts honest in every test that arms one).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageUntyped request — convert by adding bug / feature / epic

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions