Runtime Overview
The Runtime interface is the abstraction that decouples actor code from the
underlying concurrency mechanism. All scheduling, mailbox creation, and
fiber/coroutine management flow through this single interface, making actor
behaviors completely portable between runtimes.
The Runtime interface
namespace Monadial\Nexus\Core\Runtime;
interface Runtime
{
public function name(): string;
public function createMailbox(MailboxConfig $config): Mailbox;
public function spawn(callable $actorLoop): string;
public function scheduleOnce(Duration $delay, callable $callback): Cancellable;
public function scheduleRepeatedly(Duration $initialDelay, Duration $interval, callable $callback): Cancellable;
public function yield(): void;
public function sleep(Duration $duration): void;
public function run(): void;
public function shutdown(Duration $timeout): void;
public function isRunning(): bool;
}
Each method serves a specific role in the actor lifecycle:
name()-- Returns a string identifier for the runtime ('fiber','swoole', or'step').createMailbox()-- Creates a runtime-specificMailboximplementation from aMailboxConfig.spawn()-- Registers a callable as a new concurrent task (fiber or coroutine) and returns an identifier string.scheduleOnce()-- Schedules a one-shot callback after$delay. Returns aCancellablehandle.scheduleRepeatedly()-- Schedules a recurring callback with an initial delay and a fixed interval. Returns aCancellablehandle.yield()-- Cooperatively yields execution to other tasks.sleep()-- Suspends the current task for the givenDuration.run()-- Starts the event loop. Blocks until all tasks and timers complete orshutdown()is called.shutdown()-- Signals the runtime to stop within the given timeout.isRunning()-- Returns whether the event loop is currently active.
Three implementations
Nexus ships with three runtime implementations:
| Runtime | Class | Extension required | Concurrency model | Use case |
|---|---|---|---|---|
| Fiber | FiberRuntime | None | PHP 8.1+ native Fibers | Development |
| Swoole | SwooleRuntime | Swoole 5.0+ | Swoole coroutines | Production |
| Step | StepRuntime | None | Manual stepping (Fibers internally) | Testing |
All three implement the Runtime interface identically. Actor code never
references a specific runtime class -- it depends only on the Runtime
interface and the core abstractions (Mailbox, Cancellable, Duration).
Runtime pluggability
The runtime is injected at the composition root when creating an ActorSystem:
use Monadial\Nexus\Core\Actor\ActorSystem;
use Monadial\Nexus\Runtime\Fiber\FiberRuntime;
$system = ActorSystem::create('my-system', new FiberRuntime());
Switching to Swoole in production requires changing only this one line:
use Monadial\Nexus\Runtime\Swoole\SwooleRuntime;
use Monadial\Nexus\Runtime\Swoole\SwooleConfig;
$system = ActorSystem::create('my-system', new SwooleRuntime(new SwooleConfig()));
For deterministic testing, use the Step runtime with its virtual clock:
use Monadial\Nexus\Runtime\Step\StepRuntime;
$runtime = new StepRuntime();
$system = ActorSystem::create('test-system', $runtime, clock: $runtime->clock());
All actor behaviors, Props definitions, and supervision strategies remain identical across runtimes.
When to use which
StepRuntime is the right choice when:
- You are writing unit or integration tests for actor behavior.
- You need deterministic, reproducible message processing order.
- You need to control time (advance virtual clock, trigger timers on demand).
- You want to verify state after each individual message.
FiberRuntime is the right choice when:
- You are developing locally and do not want to install extensions.
- Your application handles moderate concurrency (tens to hundreds of actors).
- You are running single-process CLI tools or simple services.
- You need a zero-dependency setup for CI pipelines.
SwooleRuntime is the right choice when:
- You are running in production with high-concurrency requirements.
- Your workload involves thousands of concurrent actors or 100K+ connections.
- You need true async I/O via Swoole's coroutine hooking (database, HTTP, filesystem).
- You need multi-process scaling to utilize all CPU cores.