clock
Clock: the time as a seam, monotonic clocks, and Hybrid Logical Clocks
Clocks a test can drive: Clockwork reads the time and runs work later, the monotonic clocks never step back, and the Hybrid Logical Clock orders events across processes.
Rationale
Why. Code that reads the wall clock directly cannot be tested without it, and cannot order events by it: the wall clock steps back when NTP corrects it or someone sets it.
Problem. A timed sleep, poll or wait races the real clock, so its test is flaky under load. Across processes, no two clocks agree closely enough to order events by their readings alone.
Solution. Take time as a type. Clockwork is an InstantSource that also runs work after a delay, so a test hands in a clock it advances itself. A monotonic clock is a software.visionary.counter.Increasing that never steps back. A Hybrid Logical Clock, after Kulkarni et al. (2014), stamps each event to follow every stamp it issued or received before, while staying close to physical time.
Key Concepts
Clockwork
Role. Reads the time, as an InstantSource, and runs then on a thread of its own once delay has passed by this clockwork: after(delay, then). A zero delay is as soon as possible.
Pattern. Strategy
WallClock
Role. The system's Clockwork, WallClock.INSTANCE: instant() is the wall clock, and each piece of work that comes due runs on a virtual thread of its own, so a slow one never delays another.
Pattern. Singleton
MonotonicWallClockFactory
Role. Supplies clocks that track the wall but never step back: each next() is the later of the wall's reading and every time the clock already issued.
MonotonicClockFactory
Role. Supplies clocks that never step back because they read the wall once: each is anchored to one wall reading and advanced by a monotonic nanosecond source, such as System::nanoTime.
HybridLogicalClock
Role. Stamps a local event with next() and a message's arrival with receive(peer). Each stamp follows every stamp the clock issued or received before.
HybridTimestamp
Role. A physical time and a logical counter. Stamps order by physical time, then by counter.
HybridLogicalClockFactory
Role. Supplies Hybrid Logical Clocks over a physical clock, which may step back, and a strictly increasing counter for stamps that share a physical time.
How It Works
Guarantees. No public parameter takes null and no public method returns it, declared with contrax's @PreCondition(IsNotNull.class) and @PostCondition(IsNotNull.class). A monotonic clock's next() is never earlier than the one before. A Hybrid Logical Clock's stamp is later than every stamp it issued or received before.
Lane
Purpose. Reading time, waiting on it, and ordering events through types a test drives by hand.
Alternative. java.time.Clock, when nothing waits on time. Vector clocks, when concurrent events must be detected rather than ordered.
Usage
Running work at a time
clockwork.after(Duration.between(clockwork.instant(), due), this::wake);A wall-accurate time that never steps back
Increasing<Instant> clock = new MonotonicWallClockFactory<>(Instant::now).get();
Instant now = clock.next();Stamping messages between processes, given successors: a counter that starts after the value given, or at its first value given none
HybridLogicalClock<Instant, Long> clock = new HybridLogicalClockFactory<Instant, Long>(Instant::now, successors).get();
HybridTimestamp<Instant, Long> sent = clock.next();
HybridTimestamp<Instant, Long> arrived = clock.receive(peer);Dependencies
software.visionary:counter:2026.10.13at Compilesoftware.visionary:junit-closure:2026.09.17at Testing
Caveats
- A clock from
MonotonicClockFactorydrifts from the wall over long spans, since it reads the wall only once. - A Hybrid Logical Clock is only as close to real time as its peers: a stamp received from a peer whose clock runs ahead carries every later stamp ahead with it.
WallClock's threads never keep a program running: work still waiting for its delay when the program exits never runs, and work already running is cut off.
Views
Drawn from the release. A link in a view opens its source at the release tag.