Skip to content

Clock

  • Start here: Virtual clock
  • Common recipes: install a VirtualClock and call clock.advance(seconds) to drive time-dependent primitives without real waiting. monotonic() and sleep() are the seam primitives read through.

grelmicro.clock

Clock abstraction for time-dependent primitives.

monotonic() and sleep() resolve the active clock. Production code uses the real clock with no setup. Tests install a VirtualClock to drive time-dependent behavior without real waiting.

VirtualClock

VirtualClock(*, start: float = 0.0, name: str = 'default')

A manually advanced clock for time-dependent tests.

monotonic() returns virtual time and sleep() suspends until the virtual time is advanced past its deadline, so a retry budget, a breaker half-open window, or a rate limiter refill can be driven instantly instead of waiting real seconds.

Register it on an app or install it directly, then advance time by hand:

clock = VirtualClock()
micro = Grelmicro(uses=[clock, CircuitBreakerRegistry(...)])

async with micro:
    await call()              # trips the breaker
    await clock.advance(30)   # half-open window elapses, no real wait
    await call()              # retried

Time-dependent primitives read the active clock through grelmicro's time seam. Code that calls asyncio.sleep or time.monotonic directly is not affected.

Initialize the virtual clock at start.

PARAMETER DESCRIPTION
start

Initial value of the virtual monotonic clock, in seconds.

TYPE: float DEFAULT: 0.0

name

Registration name when used as a component.

TYPE: str DEFAULT: 'default'

kind class-attribute

kind: str = 'clock'

name property

name: str

Return the registration name.

monotonic

monotonic() -> float

Return the current virtual time.

sleep async

sleep(seconds: float) -> None

Suspend until the virtual time is advanced past seconds from now.

advance async

advance(seconds: float) -> None

Move the clock forward and wake every sleeper whose deadline passed.

PARAMETER DESCRIPTION
seconds

How far to move the virtual clock forward, in seconds.

TYPE: float

RealClock

RealClock(*, name: str = 'default')

The production clock: time.monotonic and asyncio.sleep.

This is the default behavior even when no clock is registered. Register it explicitly (Grelmicro(uses=[RealClock()])) only to make the choice visible, or to shadow a VirtualClock in a nested scope.

Initialize the clock.

PARAMETER DESCRIPTION
name

Registration name when used as a component.

TYPE: str DEFAULT: 'default'

kind class-attribute

kind: str = 'clock'

name property

name: str

Return the registration name.

monotonic

monotonic() -> float

Return time.monotonic().

sleep async

sleep(seconds: float) -> None

Sleep with asyncio.sleep().

ClockBackend

Bases: Protocol

Clock Backend Protocol.

Owns the two time operations grelmicro primitives depend on: reading a monotonic clock and sleeping. The default RealClock forwards to time.monotonic and asyncio.sleep. A VirtualClock replaces both with a manually advanced virtual timeline so time-dependent code runs without real waiting in tests.

monotonic

monotonic() -> float

Return the current value of a monotonic clock, in seconds.

sleep async

sleep(seconds: float) -> None

Suspend the current task for seconds of this clock's time.

monotonic

monotonic() -> float

Return the active clock's monotonic time, or time.monotonic().

sleep async

sleep(seconds: float) -> None

Sleep on the active clock, or asyncio.sleep() when none is installed.