PHP CLI workers don’t share opcache, so I made them: 70–80% less memory for Laravel queues
PHP's CLI doesn't share opcache between separately started processes, so every long-running worker compiles your whole app into its own private memory. With 8 Laravel queue workers that's 8 copies of the same compiled code, often 50–80 MB each.
I built queue-prefork to fix that for Laravel's queue:work and Horizon:
- A small template process starts with opcache and no app code.
- Each worker is forked from it with
pcntl_fork()and then boots the app itself from the normalartisanentry. So nothing booted is inherited: no DB or Redis connections, sockets, singletons or RNG state. Only the compiled code is shared, through opcache's shared memory. - The pid your process manager started stays (a tiny
/bin/shstub forqueue:work), so supervisord or systemd signals, timeouts and restarts behave as before.
Side-by-side benchmark, two identical Docker stacks on the same job stream, Laravel 13 with ~45 packages, 1 h each:
| Setup | Stock | Prefork |
|---|---|---|
| 8 × queue:work, typical jobs | 645 MB | 192 MB (−70%) |
| 8 × queue:work, idle | 455 MB | 102 MB (−78%) |
| 8 × queue:work, heavy jobs | 1,025 MB | 524 MB (−49%) |
| Horizon, 6 supervisors | 1,279 MB | 240 MB (−81%) |
Same throughput, 0 failed jobs, and less CPU, since new workers don't recompile anything. If any safety check fails, workers run as stock and the package tells you why.
Linux only for production; Laravel 11–13. MIT: https://github.com/tevkert/queue-prefork
Happy to answer questions about the fork and opcache side.
[link] [comments]