phyra / workerman-bridge
Phyra — Run Laravel on Workerman. Fast, memory-safe, state-leak-aware, with a cross-platform control plane that works on Windows too.
Requires
- php: ^8.3
- illuminate/config: ^13.0
- illuminate/console: ^13.0
- illuminate/container: ^13.0
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/events: ^13.0
- illuminate/http: ^13.0
- illuminate/support: ^13.0
- illuminate/view: ^13.0
- workerman/workerman: ^5.2
Requires (Dev)
- laravel/framework: ^13.0
- orchestra/testbench: ^11.0
- phpunit/phpunit: ^11.5|^12.0
Suggests
- ext-event: Recommended for better Workerman event-loop performance
- ext-pcntl: Required for multi-process workers, signals and smooth reload on Linux/macOS
- ext-posix: Required for process control on Linux/macOS
- ext-redis: Required when using the Redis cache/session driver
- ext-swoole: Optional event driver for Workerman
- ext-swow: Optional event driver for Workerman
This package is auto-updated.
Last update: 2026-08-07 06:17:27 UTC
README
____ _ ____ _
| _ \(_)___ _ __ | _ \| | _____ __
| |_) | / __|| '_ \ | |_) | |/ _ \ \ /\ / /
| __/| \__ \| |_) | | __/| | (_) \ V V /
|_| |_|___/| .__/ |_| |_|\___/ \_/\_/
|_|
Run Laravel on Workerman. Fast. Memory-safe. State-leak-aware.
Laravel Octane supports FrankenPHP, Swoole and RoadRunner — but not Workerman. Phyra fills that gap with an Octane-style sandbox engine and a control plane that works on Linux and Windows.
Quick Start · Why Phyra? · Configuration · Docs · FAQ
⚡ Quick Start
composer require phyra/workerman-bridge php artisan vendor:publish --tag=phyra-config php artisan phyra:serve
That's it. Your Laravel app now runs on a persistent Workerman process. No code changes required for most applications.
____ _ ____ _ | _ \(_)___ _ __ | _ \| | _____ __ | |_) | / __|| '_ \ | |_) | |/ _ \ \ /\ / / | __/| \__ \| |_) | | __/| | (_) \ V V / |_| |_|___/| .__/ |_| |_|\___/ \_/\_/ |_| Laravel on Workerman — fast, memory-safe, state-leak-aware. Host: 0.0.0.0 Port: 8080 Workers: auto-detect Max req: 10000 per worker
📦 Not on Packagist yet? Install from GitHub instead — see Installation.
🤔 Why Phyra?
Laravel is the most productive PHP framework. Workerman is a fast, persistent PHP application server written in pure PHP (no extra extensions required on Windows). They're a great combo — but Laravel assumes a fresh process per request, while Workerman keeps your app alive forever.
Phyra bridges that gap with a proper state management engine so your Laravel app runs safely inside a long-lived worker.
| Feature | PHP-FPM | Octane (Swoole) | Phyra (Workerman) |
|---|---|---|---|
| Persistent process (no boot per request) | ❌ | ✅ | ✅ |
| Pure PHP (no C extensions) | ✅ | ❌ | ✅ |
| Works on Windows | ✅ | ❌ | ✅ |
| Multi-process workers | ✅ | ✅ | ✅ (Linux) |
| Stop / status / reload commands | n/a | ✅ | ✅ (cross-platform) |
| Sandbox state isolation | ❌ | ✅ | ✅ |
| Drop-in for existing Laravel app | ✅ | ⚠️ caveats | ⚠️ caveats |
Phyra is independent and not affiliated with Laravel Octane, though it borrows the well-tested sandbox pattern. The same Octane compatibility rules apply — see State leaks & limitations.
✨ Features
- Octane-style sandbox — clones the app per request, rebinds the Kernel & Router to the sandbox, then restores them. Config / locale / container / facade / view / session / auth state is isolated between requests.
- Cross-platform control plane —
phyra:status,phyra:stopandphyra:reloadwork on Windows too (via a pid + heartbeat + stop-sentinel mechanism), not just on Linux. - Persistent DB connections — connections stay alive across requests with auto-reconnect on dead sockets and automatic rollback of leaked transactions.
- Worker recycling — workers are recycled after N requests or when they exceed a memory limit, preventing slow memory growth.
- Hot reload in development — file monitor reloads on code changes (smooth on Linux, full-stop on Windows).
- Laravel-native — registers as a ServiceProvider + Facade, publishes a config file, ships Artisan commands. Feels like part of Laravel.
🏗️ How It Works
┌─────────────────────────────────────────────────────────┐
│ Your Laravel 13.x app (unchanged) │
├─────────────────────────────────────────────────────────┤
│ Phyra State Engine │
│ ├── Per request: clone base app → sandbox │
│ ├── Rebind HTTP Kernel + Router → sandbox │
│ ├── Handle request through sandbox │
│ ├── Restore Kernel + Router → base app │
│ ├── Flush sandbox + reset base state │
│ │ · config · locale · facades · view cache │
│ │ · container scoped · session · auth │
│ └── Worker recycle (max requests + memory limit) │
├─────────────────────────────────────────────────────────┤
│ Database / Redis │
│ ├── Persistent connections across requests │
│ ├── Auto-reconnect on dead connections │
│ └── Auto-rollback leaked transactions │
├─────────────────────────────────────────────────────────┤
│ Workerman 5.2 (persistent HTTP server, pure PHP) │
└─────────────────────────────────────────────────────────┘
A deep dive is in docs/architecture.md.
📊 Benchmark
Run the included benchmark against your own app and compare with PHP-FPM:
# Start Phyra php artisan phyra:serve --port=8080 # Benchmark it (requires `wrk`) wrk -t4 -c64 -d30s http://localhost:8080 # Compare with artisan serve / PHP-FPM php artisan serve --port=8000 wrk -t4 -c64 -d30s http://localhost:8000
Or use the bundled script:
php benchmark/run.php http://localhost:8080 10 64
Real numbers depend entirely on your app, hardware, and workload — so measure your own. As a baseline reference, a trivial "hello world" route on a single Windows worker handled ~120 req/s with zero memory growth across 500 requests in our smoke test. On Linux with multiple workers and a real workload, throughput scales roughly linearly with worker count.
See docs/benchmark.md for a honest methodology.
🛠️ Configuration
Publish the config:
php artisan vendor:publish --tag=phyra-config
// config/phyra.php return [ 'server' => [ 'host' => env('PHYRA_HOST', '0.0.0.0'), 'port' => env('PHYRA_PORT', 8080), 'workers' => env('PHYRA_WORKERS', null), // auto on Linux, 1 on Windows 'name' => env('PHYRA_SERVER_NAME', 'Phyra'), 'control_dir' => env('PHYRA_CONTROL_DIR', null), // null = storage/framework/phyra ], 'worker' => [ 'max_requests' => env('PHYRA_MAX_REQUESTS', 10000), // recycle after N 'memory_limit' => env('PHYRA_MEMORY_LIMIT', '128M'), // recycle if exceeded 'reload' => env('PHYRA_RELOAD', false), ], 'file_monitor' => [ 'enabled' => env('PHYRA_FILE_MONITOR', null), // null = auto (on when APP_DEBUG) 'extensions' => ['php', 'env', 'html', 'htm'], 'poll_interval' => 1, ], 'state' => [ 'flush' => ['config' => true, 'locale' => true, 'facade' => true, 'view' => true, 'container' => true, 'request' => true], ], 'database' => [ 'auto_reconnect' => true, 'rollback_leaked_transactions' => true, ], ];
Full reference: docs/configuration.md.
🧑💻 Commands
php artisan phyra:serve # Start the server php artisan phyra:status # Is it running? (cross-platform) php artisan phyra:stop # Stop the server (cross-platform) php artisan phyra:reload # Smooth restart (Linux) / full stop (Windows)
You can also use the Phyra Facade in your app:
use Phyra\Workerman\Facades\Phyra; if (Phyra::isRunning()) { // running inside a Phyra worker }
🪟 Platform Support
Phyra runs on both Linux and Windows. Workerman itself has different capabilities per platform — be aware of the differences:
| Capability | Linux / macOS | Windows |
|---|---|---|
| Multiple worker processes | ✅ yes | ❌ single process only |
pcntl / posix (signals) |
✅ required | ❌ not available |
phyra:stop |
✅ SIGTERM | ✅ via stop-sentinel file |
phyra:reload (smooth) |
✅ SIGUSR1 | ⚠️ full stop (restart externally) |
phyra:status |
✅ pid + posix check | ✅ heartbeat-based check |
| Daemon / background | ✅ yes | ❌ runs in the terminal |
| File-monitor hot reload | ✅ smooth reload | ⚠️ full stop on change |
Windows is great for development. For production, run on Linux to get multi-process workers, daemonization and smooth reload. More in docs/windows.md.
🧪 Testing
composer test
The suite covers real state isolation (config/locale don't leak across requests), the cross-platform control plane, DB connection pool safety, command registration, and worker recycling.
❓ FAQ
Is Phyra a drop-in replacement for PHP-FPM?
For most apps, yes. But because the worker stays alive between requests, you
must follow the same rules as Laravel Octane — avoid static variables in
route closures, don't accumulate listeners per request, etc. See
State leaks & limitations.
How is this different from Laravel Octane?
Octane supports FrankenPHP, Swoole and RoadRunner — not Workerman. Phyra is an independent bridge that targets Workerman specifically. It uses the same sandbox pattern as Octane, so the same compatibility rules apply.
Does it work on Windows?
Yes — including phyra:status and phyra:stop, which normally require POSIX
signals. Phyra ships a cross-platform control plane (pid + heartbeat +
stop-sentinel). Windows is limited to a single worker process and no smooth
reload, so use Linux for production.
Will my static counter leak between requests?
Yes — that's a fundamental PHP limitation, not something any bridge can fix. Move shared state to the cache or database. See State leaks & limitations.
Where are the control files written?
To storage/framework/phyra/ by default (phyra.pid, phyra.heartbeat,
phyra.stop). Override with PHYRA_CONTROL_DIR.
🗺️ Roadmap
- Packagist publication (
composer require phyra/workerman-bridge) - WebSocket / async support via Workerman protocols
- Optional Octane-compatible runtime interface
- CI on Linux + Windows
- More integration tests with real Laravel features (queues, mail, broadcasts)
🤝 Contributing
Contributions are welcome! Please read CONTRIBUTING.md and the Code of Conduct before opening a PR.
📄 License
MIT — see LICENSE.
If Phyra saves you boot time per request, give it a ⭐ to help others find it.