nexphant/runtime
Core persistent runtime engine. Manages workers, fiber event loop, connection pools, adaptive pressure control, and graceful shutdown.
Install
composer require nexphant/runtimeWhat's Included
- Worker — persistent worker process with exponential error backoff
- FiberEventLoop — cooperative concurrency scheduler using PHP Fibers
- ConnectionPool — fiber-aware connection pooling with waiter queue
- AdaptiveRuntime — pressure-aware accept rate controller
- SharedWorkerTable — cross-process worker stats via shared memory
Worker
Each worker runs a persistent event loop, accepting connections and dispatching requests.
use Nexphant\Runtime\Worker;
$worker = new Worker($server, $loop, options: [
'max_backoff' => 60, // max error backoff in seconds
]);
$worker->run();On consecutive errors, the worker applies exponential backoff (2^n seconds, capped at max_backoff). The backoff resets when a request completes successfully.
FiberEventLoop
The event loop schedules fibers cooperatively. Sleeping fibers are managed with a priority heap for O(log n) wake-up scheduling.
use Nexphant\Runtime\FiberEventLoop;
$loop = new FiberEventLoop();
// Sleep a fiber for N milliseconds
$loop->sleepFiber($fiber, milliseconds: 250);
// Run the event loop
$loop->run();Timers and sleeping fibers are drained in wake-time order, minimizing unnecessary iterations.
ConnectionPool
Fiber-aware pool. Callers that cannot immediately acquire a connection are queued and resumed when one is released.
use Nexphant\Runtime\ConnectionPool;
// Register a pool factory
ConnectionPool::register('db', function () {
return new PDO('sqlite:storage/app.db');
}, size: 10);
// Acquire — suspends the current fiber if pool is exhausted
$conn = ConnectionPool::acquire('db');
// Release back to pool (resumes next waiter automatically)
ConnectionPool::release('db', $conn);No busy-wait. Waiters are served FIFO when a connection is released.
AdaptiveRuntime
Monitors system pressure and adjusts the accept rate per tick to prevent overload.
use Nexphant\Runtime\Adaptive\AdaptiveRuntime;
$runtime = new AdaptiveRuntime($stats);
// Get current pressure score (0.0 – 1.0)
$pressure = $runtime->pressure();
// Get recommended accept limit for this tick
$limit = $runtime->acceptLimit();Pressure is calculated once per tick and cached — subsequent calls within the same tick read the cached value.
SharedWorkerTable
Reads all worker stats from shared memory in a single bulk read with one lock acquire, minimising contention.
use Nexphant\Runtime\Adaptive\SharedWorkerTable;
$table = new SharedWorkerTable($shmKey, $workerCount);
// Write stats for this worker
$table->write($workerId, $stats);
// Read all worker stats — single lock, bulk read
$allStats = $table->readAll();Runtime Options
| Option | Default | Description |
|---|---|---|
workers | 4 | Number of worker processes |
max_backoff | 60 | Max error backoff in seconds per worker |
event_loop | auto | Event loop backend (auto, ev, event, native) |
socket_driver | native | Socket backend (native, uv) |
max_accept_per_tick | 32 | Max connections accepted per event loop tick |
keep_alive_timeout | 30 | HTTP keep-alive timeout in seconds |
