infocyph / runwire
A high-performance process and network runtime for PHP.
Requires
- php: ^8.4
- php-64bit: ^8.4
Requires (Dev)
- ext-pcntl: *
- ext-posix: *
- infocyph/phpforge: dev-main@dev
Suggests
- ext-event: Enables custom accelerated LoopInterface adapters while Runwire falls back to SelectLoop.
- ext-openssl: Enables native TLS listeners and HTTP/2 ALPN negotiation.
- ext-openswoole: Enables the OpenSwoole host runtime and coroutine/event-loop integration.
- ext-pcntl: Enables native prefork workers, signal handling, reloads and process supervision.
- ext-posix: Enables native process signaling, identity handling and privilege dropping.
- ext-quic: Enables native QUIC transport and HTTP/3 serving.
- ext-sockets: Enables optional low-level socket capabilities and transport tuning.
- ext-swoole: Enables the Swoole host runtime and coroutine/event-loop integration.
- ext-zend-opcache: Enables persistent bytecode caching for lower startup and runtime overhead.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-18 02:29:52 UTC
README
A high-performance, framework-agnostic process and network runtime for PHP.
Runwire provides the low-level runtime boundary for process supervision, event loops, native network servers, HTTP/1.1/2/3, host-runtime adaptation, structured coroutines, bounded lifecycle management, and production diagnostics. It is designed to be embedded by frameworks and applications rather than becoming an application framework itself.
Runwire 1.0 is the release line targeted by Foundation 3.
Requirements
Hard package requirements:
- 64-bit PHP
^8.4; - Composer.
Install:
composer require infocyph/runwire
Optional runtime capabilities:
| Extension/capability | Enables |
|---|---|
ext-pcntl + ext-posix |
native prefork supervision, reload, worker replacement/recycle, signals, control operations, privilege reduction |
ext-openssl |
native TLS and HTTP/2 ALPN |
ext-quic |
native QUIC / HTTP/3 |
ext-swoole / ext-openswoole |
Swoole/OpenSwoole host runtime integration; select RuntimeDriver::SWOOLE explicitly when using this host adapter |
ext-sockets |
optional low-level socket features |
| OPcache | persistent bytecode caching |
Without PCNTL/POSIX, native CLI uses Runwire's portable single-process runtime. Prefork-only capabilities are not advertised there.
Native HTTP quick start
<?php declare(strict_types=1); use Infocyph\Runwire\Http\HttpRequest; use Infocyph\Runwire\Http\ResponseWriterInterface; use Infocyph\Runwire\Runtime; use Infocyph\Runwire\Server; require __DIR__ . '/vendor/autoload.php'; $server = Server::http( '127.0.0.1:8080', static function (HttpRequest $request, ResponseWriterInterface $writer): void { $writer->end("Hello from Runwire\n"); }, ); Runtime::create() ->listen($server) ->run();
Run:
php server.php curl http://127.0.0.1:8080/
Runtime modes
RuntimeDriver::AUTO detects active hosted environments and native CLI capability. The built-in environment probe recognizes active FrankenPHP, RoadRunner, and FPM hosts; otherwise eligible CLI execution resolves to native Runwire. Merely installing Swoole/OpenSwoole does not mark the process as an active Swoole host, so use explicit RuntimeDriver::SWOOLE selection when Runwire should use its Swoole/OpenSwoole host adapter.
| Runtime | Listener/wire owner | Application lifetime | Worker pool |
|---|---|---|---|
| Native prefork | Runwire | persistent | Runwire |
| Native portable | Runwire | persistent | single process |
| FPM | web server / FPM | request-scoped from Runwire boundary | host |
| FrankenPHP | FrankenPHP | host/mode dependent | host |
| RoadRunner | RoadRunner | persistent | host |
| Swoole/OpenSwoole | Swoole/OpenSwoole | persistent | host |
Native listeners use:
Runtime::create()->listen($server)->run();
Auto-detected host-owned runtimes use:
Runtime::create()->serve($handler);
or:
Runtime::create()->serveApplication($applicationFactory);
Swoole/OpenSwoole uses the same host-owned serving API, but select the driver explicitly:
use Infocyph\Runwire\Runtime; use Infocyph\Runwire\Runtime\Enum\RuntimeDriver; use Infocyph\Runwire\RuntimeOptions; use Infocyph\Runwire\SwooleOptions; $options = new RuntimeOptions( driver: RuntimeDriver::SWOOLE, swoole: new SwooleOptions( host: '127.0.0.1', port: 9501, ), ); Runtime::create($options)->serve($handler);
Either supported Swoole-family extension can back RuntimeDriver::SWOOLE. Explicit selection fails startup when neither runtime is available.
Do not combine host-owned serving with a competing Runwire listener.
Portable native contract
Portable native is intentionally not a substitute supervisor:
workers 0 or 1 one process
workers > 1 startup error
enabled recycle threshold startup error
control endpoint startup error
development watcher startup error
lifecycle listener startup error
worker privilege drop startup error
HTTP/3 without QUIC startup error
HTTP/1.1, framed TCP/Unix, and UDP remain available when their platform capabilities are present. External supervision owns process restart/replacement.
Native protocols
Runwire 1.0 provides:
- HTTP/1.1 over TCP/TLS;
- HTTP/2 over TLS ALPN with HTTP/1.1 fallback;
- HTTP/3 over QUIC when the supported QUIC capability is available;
- framed TCP and Unix-domain stream servers;
- UDP datagram servers.
All native HTTP versions normalize to the same application-facing HttpRequest / ResponseWriterInterface contract.
TLS / HTTP/2
use Infocyph\Runwire\Network\TlsOptions; $tls = new TlsOptions( localCertificate: __DIR__ . '/certs/server.crt', privateKey: __DIR__ . '/certs/server.key', ); $server = Server::http('0.0.0.0:8443', $handler) ->withTls($tls);
Default ALPN is h2,http/1.1. Explicit TLS configuration fails when OpenSSL capability is unavailable; it never becomes plaintext silently.
HTTP/3
$server = Server::http('0.0.0.0:8443', $handler) ->withTls($tls) ->withHttp3();
HTTP/3 requires TLS plus the supported QUIC capability. Explicit HTTP/3 without QUIC fails startup; it is never silently ignored. 0-RTT application dispatch is disabled in Runwire 1.0.
Framed TCP example
use Infocyph\Runwire\Protocol\FramedConnection; use Infocyph\Runwire\Protocol\LineCodec; use Infocyph\Runwire\StreamServer; $server = StreamServer::tcp( '127.0.0.1:9000', static fn(): LineCodec => new LineCodec(), static function (string $frame, FramedConnection $connection): void { $connection->send('echo:' . $frame); }, ); Runtime::create()->listen($server)->run();
Structured coroutines
Runwire includes a lightweight structured-concurrency runtime built on PHP Fiber and LoopInterface.
use Infocyph\Runwire\Coroutine\CoroutineRuntime; use Infocyph\Runwire\Coroutine\CoroutineScope; $coroutines = new CoroutineRuntime(); $result = $coroutines->run( static function (CoroutineScope $scope): array { $left = $scope->spawn(static function () use ($scope): string { $scope->sleep(0.010); return 'left'; }); $right = $scope->spawn(static fn(): string => 'right'); return [$left->await(), $right->await()]; }, );
Structured ownership means a scope does not silently finish while owned children remain live. Cancellation and deadlines propagate through the ownership tree.
Available scheduler-aware primitives include:
- tasks and nested groups;
- futures/deferred values;
- bounded channels;
- semaphores and mutexes;
- barriers;
- task-local state;
- cooperative sleep/yield;
- readable/writable stream waiting;
- request-scoped coroutine execution;
- worker-generation background work;
- coroutine-friendly
AsyncConnectionadaptation.
Runwire does not make arbitrary blocking PHP APIs asynchronous.
Runtime and request context
RuntimeContext contains immutable worker/application-lifetime facts:
driver / mode
worker slot / generation / PID
persistence / concurrency
listener / event-loop / worker-pool ownership
resolved capabilities
runtime metrics
RequestContext contains request-lifetime state:
request ID
monotonic start/deadline
cancellation token
bounded request attributes
owning RuntimeContext
Framework integrations should use capability checks instead of driver-name branching for generic behavior:
use Infocyph\Runwire\Runtime\Enum\RuntimeCapability; if ($context->supports(RuntimeCapability::PERSISTENT)) { // worker-lifetime application state is allowed } $context->requireCapability(RuntimeCapability::RUNWIRE_COROUTINES);
Application lifecycle
Managed applications follow:
boot
→ warmup
→ ready
→ handle
→ reset
→ ...
→ drain
→ shutdown
Frameworks can implement RuntimeApplicationFactoryInterface so application construction happens after the concrete runtime context/capabilities are known.
Request cleanup is part of the persistent-runtime security boundary. Framework adapters must reset framework-owned request-local state after every request, including failure/cancellation/deadline paths.
Worker lifecycle
Native prefork supports:
- readiness tracking;
- bounded startup/readiness timeouts;
- process restart/backoff;
- rolling reload;
- worker recycle/replacement;
- lifecycle events;
- optional control socket;
- optional development watcher;
- optional privilege reduction.
When UID-based privilege reduction is configured, Runwire resolves the target account, initializes supplementary groups, sets GID before UID, verifies the final effective identity, and only then proceeds to application bootstrap/readiness. A partial transition fails startup.
Native prefork running as root without worker privilege dropping reports a SECURITY: runtime-selection warning. Prefer starting the service unprivileged whenever possible.
Resource safety
Runwire is designed around bounded state:
- admission limits;
- listener/connection limits;
- request-body/header limits;
- HTTP/2/HTTP/3 stream limits;
- response buffering and backpressure;
- HPACK/QPACK limits;
- event-loop work budgets;
- coroutine tasks/backlogs/waiters;
- diagnostics/status payloads;
- restart/reload/recycle policies.
Treat limit increases as capacity-planning decisions and verify them with soak/load tests.
WorkerRecyclePolicy::maxMemoryBytes is based on PHP allocator memory, not process RSS/cgroup/native-extension/kernel memory. Use OS/container memory limits as the hard process-memory boundary.
Process execution
ProcessRunner executes validated argv directly with shell bypass and does not require PCNTL. Its default allowedExecutables: null means any validated absolute executable path is permitted. Security-sensitive consumers should supply an explicit executable allowlist and bound environment, cwd, stdin, output, and timeout policies.
See the security guide before exposing process execution to application-controlled input.
Performance
Repository benchmark artifacts are regression/workload evidence, not a universal runtime ranking.
Meaningful cross-runtime comparisons require equivalent:
- hardware and OS;
- PHP/runtime versions;
- protocol/TLS configuration;
- worker count and concurrency;
- workload;
- duration and instrumentation.
Report throughput together with p50/p95/p99 latency, errors, CPU, and RSS.
Documentation
Start here for complete examples and operational guidance:
docs/getting-started.md— complete native HTTP, TLS/HTTP2, HTTP3, TCP/Unix, UDP, hosted-runtime, explicit Swoole/OpenSwoole selection, application-factory, capability, and coroutine examples.docs/architecture.md— runtime selection, ownership boundaries, capability model, contexts, lifecycle, networking, protocol, coroutine, observability, and security contracts.docs/deployment.md— production topology, host selection, worker sizing, admission, deadlines, recycle/reload, control/watch, privilege drop, TLS/HTTP3, backpressure, resource limits, and deployment acceptance.docs/security.md— least privilege, persistent-state isolation, ProcessRunner policy,disable_functions, resource ceilings, and systemd/container hardening.docs/coroutines.md— full structured-concurrency API with tasks, failure modes, deadlines, channels, futures, semaphore, mutex, barrier, task-local state, request integration, background work, andAsyncConnectionexamples.docs/benchmarks.md— benchmark layers, local commands, HTTP/3 transport measurement, release evidence, peer-comparison schema, and integrity rules.docs/plans/runwire-1.0-foundation-3-launch-plan.md— final hardening status, documentation closure, exact-head certification matrix, and human-controlled release sequence.
Development
Install development dependencies:
composer install
Run repository QA:
composer ic:ci
Run the automated formatting/refactor processing pipeline:
composer ic:process
The CI matrix covers supported PHP versions/dependency modes, static analysis, clean production installation, genuine no-PCNTL portable-native acceptance, benchmarks, Swoole/OpenSwoole acceptance, and dedicated QUIC/HTTP/3 interoperability/soak lanes.
License
Runwire is released under the MIT License.