nexus-runtime-step
Deterministic runtime for testing. Manual message stepping, virtual time, and guaranteed ordering.
Composer: nexus-actors/runtime-step
Namespace: Monadial\Nexus\Runtime\Step\
Classes
StepRuntime
Implements Monadial\Nexus\Core\Runtime\Runtime.
The testing runtime. Uses PHP Fibers internally but replaces the automatic tick
loop with manual control. Each step() call processes exactly one message.
use Monadial\Nexus\Runtime\Step\StepRuntime;
$runtime = new StepRuntime();
Optionally accepts a VirtualClock:
$clock = new VirtualClock(new DateTimeImmutable('2025-01-01T00:00:00+00:00'));
$runtime = new StepRuntime($clock);
Key methods (from Runtime interface):
name(): string-- Returns'step'.createMailbox(MailboxConfig): Mailbox-- Returns a newStepMailbox.spawn(callable): string-- Creates aFiberfrom the callable and returns an ID like'step-0'.scheduleOnce(Duration, callable): Cancellable-- Stores timer with virtual fire time. ReturnsStepCancellable.scheduleRepeatedly(Duration, Duration, callable): Cancellable-- Stores repeating timer with virtual fire time.yield(): void-- No-op.sleep(Duration): void-- No-op.run(): void-- Callsdrain()(processes all pending messages).shutdown(Duration): void-- Closes all mailboxes and cleans up fibers.isRunning(): bool-- Returns whetherrun()is currently executing.
Step API:
step(): bool-- Process one message. Returnsfalseif idle.drain(): void-- Process all pending messages.advanceTime(Duration): void-- Advance virtual clock and fire due timers.
Inspection:
clock(): VirtualClock-- Returns the virtual clock instance.pendingMessageCount(): int-- Total unprocessed messages across all mailboxes.isIdle(): bool-- Whether any actor has work to do.
StepMailbox
Implements Monadial\Nexus\Core\Mailbox\Mailbox.
SplQueue-backed mailbox that always suspends the fiber in
dequeueBlocking(), even when messages are available. This guarantees each
message requires an explicit step() call to be processed.
Exposes hasWaitingFiber() and getWaitingFiber() for the runtime to query
which mailboxes have suspended actors ready to resume.
Supports all OverflowStrategy modes for bounded mailboxes.
VirtualClock
Implements Psr\Clock\ClockInterface.
Deterministic clock for testing. Starts at 2026-01-01T00:00:00+00:00 by
default.
$clock = new VirtualClock();
$clock->now(); // 2026-01-01T00:00:00+00:00
$clock->advance(Duration::seconds(5)); // move forward 5 seconds
$clock->set(new DateTimeImmutable(...));// jump to a specific time
StepCancellable
Implements Monadial\Nexus\Core\Actor\Cancellable.
Simple boolean-flag cancellable. Calling cancel() sets the flag; timers check
it before firing and skip cancelled entries.