Laravel Octane with Swoole: container state leaking between requests
We put a mature Laravel app behind Octane on Swoole and got a 4x throughput bump, but also a class of bugs we never saw under FPM. A singleton service was caching the authenticated user, and after a while different users started seeing each other data. The framework stays booted between requests, so anything you resolved once and held onto sticks around.
I have read the Octane docs on flushing state, but I want the practical checklist. Which bindings do you mark to reset per request, and how do you find the leaky singletons before your users do?
The mental shift is that the container is no longer rebuilt per request. Octane flushes some framework state for you, but your own singletons keep whatever they cached. Anything that captures request, auth user, or session inside a singleton is a leak. The fix is usually to not cache request-scoped data in a singleton at all, resolve it fresh where you need it instead of stashing it.
Use the Octane config listeners and the flush array. You can list bindings to forget after each request, and you can register a callback on RequestReceived to reset specific services. But treat that as a safety net, not the design. If you find yourself adding more and more services to the flush list, the real problem is that those services hold state they should not.
Two more classic Octane leaks beyond auth. First, anything that reads config and caches a derived value at boot, if you change config per request via middleware it will not see it. Second, static properties on your own classes, same trap as raw Swoole, they survive across requests. Grep your codebase for static properties and treat each as guilty until proven stateless.
The flush-list-growing comment hit home, that is exactly the smell we had. We stopped caching the user in the service and instead pass it in or pull from auth at call time. Cross-user bleed gone. The throughput win is real but Octane really does demand you think about object lifetime the way the rest of us avoided for a decade under FPM.
To find them before users do, run a soak test that hammers the app as several different authenticated users concurrently and asserts each response belongs to the right user. Leaks only show up under interleaving, a single-user load test will pass happily. We added a header echoing the resolved user id and diffed it against the expected one in the load script. Caught two more singletons that way.
```php blocks are runnable.