Laravel Octane: Worker Lifecycle &amp; State Leakage | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Octane Worker Lifecycle, State Leakage, and Memory Management in Production        On this page       1. [  Why Octane Changes Everything About Application State ](#why-octane-changes-everything-about-application-state)
2. [  The Worker Lifecycle in Detail ](#the-worker-lifecycle-in-detail)
3. [  Common Leakage Patterns ](#common-leakage-patterns)
4. [  1. Singletons That Accumulate State ](#1-singletons-that-accumulate-state)
5. [  2. Static Properties ](#2-static-properties)
6. [  3. Closures Captured in Long-Lived Objects ](#3-closures-captured-in-long-lived-objects)
7. [  Memory Management ](#memory-management)
8. [  Verifying Your Code Is Octane-Safe ](#verifying-your-code-is-octane-safe)
9. [  Key Takeaways ](#key-takeaways)

  ![Octane Worker Lifecycle, State Leakage, and Memory Management in Production](https://cdn.msaied.com/440/abbd7cbb286a5bd8ea53bee583d2c30f.png)

  #laravel   #octane   #performance   #swoole   #roadrunner  

 Octane Worker Lifecycle, State Leakage, and Memory Management in Production 
=============================================================================

     18 Jul 2026      4 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

  9 sections  

1. [  01   Why Octane Changes Everything About Application State  ](#why-octane-changes-everything-about-application-state)
2. [  02   The Worker Lifecycle in Detail  ](#the-worker-lifecycle-in-detail)
3. [  03   Common Leakage Patterns  ](#common-leakage-patterns)
4. [  04   1. Singletons That Accumulate State  ](#1-singletons-that-accumulate-state)
5. [  05   2. Static Properties  ](#2-static-properties)
6. [  06   3. Closures Captured in Long-Lived Objects  ](#3-closures-captured-in-long-lived-objects)
7. [  07   Memory Management  ](#memory-management)
8. [  08   Verifying Your Code Is Octane-Safe  ](#verifying-your-code-is-octane-safe)
9. [  09   Key Takeaways  ](#key-takeaways)

       Why Octane Changes Everything About Application State
-----------------------------------------------------

Traditional PHP-FPM boots the framework on every request and discards all memory when the response is sent. Octane inverts this: a single worker process boots Laravel **once** and then handles thousands of requests in that same process. The performance gain is real — but the contract your code must honour changes completely.

Understanding the worker lifecycle is the prerequisite for running Octane safely.

The Worker Lifecycle in Detail
------------------------------

With Swoole or RoadRunner, Octane's boot sequence looks like this:

1. **Worker boot** — `Application::boot()` runs, all service providers fire, singletons are resolved and cached in the container.
2. **Request loop** — for each incoming request Octane clones a "sandbox" application, binds fresh `Request`, `Auth`, `Session`, and a handful of other stateful services, then dispatches through the kernel.
3. **Flush** — after the response is sent, Octane fires `RequestHandled` and resets the services registered in `octane.php` under `flush`.

The critical insight: **anything not in the flush list persists across requests**.

Common Leakage Patterns
-----------------------

### 1. Singletons That Accumulate State

```php
// AppServiceProvider
$this->app->singleton(ReportBuilder::class, function () {
    return new ReportBuilder();
});

// ReportBuilder.php
class ReportBuilder
{
    private array $filters = [];

    public function addFilter(string $f): static
    {
        $this->filters[] = $f; // leaks across requests!
        return $this;
    }
}

```

Request 1 adds `['status' => 'active']`. Request 2 resolves the **same** instance and sees that filter already present. Fix: make the class immutable, or register it as `scoped` instead of `singleton`.

```php
$this->app->scoped(ReportBuilder::class, fn () => new ReportBuilder());

```

`scoped` bindings are flushed by Octane automatically at the end of each request — they behave like singletons within a request but are discarded afterward.

### 2. Static Properties

```php
class TenantContext
{
    public static ?Tenant $current = null;
}

```

Octane's sandbox clone does **not** reset static class properties. If middleware sets `TenantContext::$current` and a subsequent request hits the same worker before middleware runs, it reads the previous tenant. Use `app()->scoped()` or reset explicitly in an Octane `RequestHandled` listener.

```php
// OctaneServiceProvider or EventServiceProvider
Octane::tick('reset-tenant', function () {
    TenantContext::$current = null;
});

```

### 3. Closures Captured in Long-Lived Objects

```php
$this->app->singleton(EventDispatcher::class, function ($app) {
    $d = new EventDispatcher();
    $d->listen('*', function ($event) use ($app) {
        // $app is the root container — fine.
        // but if you capture $request here, it leaks.
    });
    return $d;
});

```

Capturing the current `Request` or `Auth` object inside a singleton closure is a classic leak. Always resolve them lazily from the container at call time.

Memory Management
-----------------

Octane workers will grow in memory over time even with correct code, because PHP's garbage collector does not always collect cyclic references immediately.

**Configure `max_requests` in `octane.php`:**

```php
'swoole' => [
    'options' => [
        'max_request' => 500,
    ],
],

```

After 500 requests the worker restarts cleanly. Tune this number based on your memory growth rate — profile with `memory_get_usage()` logged in a `RequestHandled` listener.

**Use `octane:status` and Horizon-style metrics** to watch worker memory in production. A worker that grows beyond ~128 MB before its `max_requests` limit is a signal of a genuine leak.

Verifying Your Code Is Octane-Safe
----------------------------------

The `laravel/octane` package ships a `--watch` flag for development, but for correctness testing:

```bash
php artisan octane:start --workers=1 --max-requests=1000

```

Then hammer a route that exercises your singletons with `wrk` or `ab` and assert response consistency. Automated: write a Pest test that dispatches the same request twice through the kernel and asserts no state bleeds.

```php
it('does not leak filters between requests', function () {
    $kernel = app(\Illuminate\Contracts\Http\Kernel::class);

    $r1 = $kernel->handle(Request::create('/report?status=active'));
    $r2 = $kernel->handle(Request::create('/report'));

    expect($r2->getContent())->not->toContain('active');
});

```

Key Takeaways
-------------

- Use `scoped` instead of `singleton` for any service that holds per-request state.
- Never store the current `Request`, `Auth`, or `Session` in a singleton property or static variable.
- Reset static class properties in an Octane `RequestHandled` listener or `tick`.
- Set `max_requests` to recycle workers and cap worst-case memory growth.
- Profile memory growth per request in staging before deploying Octane to production.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Foctane-worker-lifecycle-state-leakage-and-memory-management-in-production-1&text=Octane+Worker+Lifecycle%2C+State+Leakage%2C+and+Memory+Management+in+Production) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Foctane-worker-lifecycle-state-leakage-and-memory-management-in-production-1) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  What is the difference between `singleton` and `scoped` in an Octane context?        A `singleton` is resolved once per worker process and persists for the entire lifetime of that worker. A `scoped` binding is resolved once per request and automatically flushed by Octane at the end of each request, making it safe for stateful per-request services. 

      Q02  Does Octane automatically reset all Laravel services between requests?        Only the services listed under the `flush` key in `config/octane.php` are reset automatically. Core stateful services like `Request`, `Auth`, and `Session` are included by default, but any custom singletons you register are your responsibility. 

      Q03  How do I detect a state leak in an Octane application?        Run a single worker with a high `max_requests` value and send the same request repeatedly with different inputs. Log the response or assert consistency in a Pest test that calls the kernel twice in the same process. Diverging responses between calls indicate leaked state. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Laravel + Python FastAPI: Image OCR Demo](https://cdn.msaied.com/447/5f3d87146fbf19957973cbc88c6c0155.png) Laravel Python FastAPI 

### Laravel + Python FastAPI: Image OCR Demo

Learn how to call a Python image OCR script from Laravel using FastAPI as the bridge. This premium tutorial wa...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 20 Jul 2026     3 min read  

  Read    

 ](https://msaied.com/articles/laravel-python-fastapi-image-ocr-demo) [ ![CQRS in Laravel Without a Framework: Commands, Handlers, and Read Models That Stay Lean](https://cdn.msaied.com/446/a05febe70b72107387f210e0f9eae089.png) laravel cqrs architecture 

### CQRS in Laravel Without a Framework: Commands, Handlers, and Read Models That Stay Lean

Skip the heavy event-sourcing libraries. This guide shows how to implement a practical CQRS layer in Laravel u...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 20 Jul 2026     1 min read  

  Read    

 ](https://msaied.com/articles/cqrs-in-laravel-without-a-framework-commands-handlers-and-read-models-that-stay-lean) [ ![Laravel Event Sourcing: Projections, Snapshots, and Replay Without the Framework Tax](https://cdn.msaied.com/445/b4f83e0b5da7c11e2fe942eebc1cad08.png) laravel event-sourcing ddd 

### Laravel Event Sourcing: Projections, Snapshots, and Replay Without the Framework Tax

Event sourcing in Laravel without a heavy framework. Build lean projectors, snapshot aggregates at scale, and...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 19 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-event-sourcing-projections-snapshots-and-replay-without-the-framework-tax) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
