Laravel Octane

repository·2.x·Indexed 26 days ago

https://github.com/laravel/octane

A high-performance application server integration for Laravel that boosts speed by keeping the application in memory between requests. It supports application servers including FrankenPHP, Open Swoole, Swoole, and RoadRunner. Octane provides features such as concurrent task execution, high-performance in-memory caching via OctaneStore, and specialized worker management to optimize Laravel application performance.

Tokens
5.7K
Snippets
13
Records
38
Agent score
87%

What's inside Laravel Octane

  1. Introduction to Laravel Octane

    2.x
    Laravel Octane is a performance enhancement package that supercharges your application by serving it using high-powered application servers. Instead of booting the entire Laravel framework for every incoming request, Octane boots your application once, keeps it in memory, and then feeds it requests, resulting in significantly higher performance.
  2. Test Octane applications correctly

    2.x

    When testing applications designed for Octane, follow these patterns to ensure state isolation and driver compatibility:

    • Simulate Request Lifecycle: Call $this->refreshApplication() between assertions to simulate the flushing of scoped bindings and verify that state does not leak.
    • Concurrency Testing: When exercising concurrently(), tables, or ticks, test for functional correctness rather than parallelism, as closures may run sequentially in a test environment.
    • Driver Guards: Guard Swoole-specific tests by checking for the extension: extension_loaded('swoole') || extension_loaded('openswoole').
  3. Detect the active Octane driver

    2.x

    Before using driver-specific features like concurrency or Swoole Tables, determine which server is running by checking the octane.server configuration key. This prevents errors when running on drivers like RoadRunner or FrankenPHP that do not support Swoole-specific APIs.

    Supported drivers are: swoole, roadrunner, or frankenphp.

    config('octane.server')
  4. Manage memory and prevent leaks in long-running workers

    2.x

    Since workers are long-lived, unreferenced objects will accumulate and eventually crash the worker. Follow these practices to manage memory:

    • Set Recycle Limits: Configure max-requests or max-jobs as a safety mechanism to recycle workers periodically.
    • Avoid Request-Level Registration: Register event listeners in Service Providers, never inside request handlers, as the dispatcher will retain them indefinitely.
    • Clear Static Collections: Never append to static arrays inside request handlers. Instead, clear them in a lifecycle listener or by adding the service to the flush list.
    • Watch Closures: Be cautious of singletons that capture large objects (like Eloquent models) within closures, as these will be held in memory forever.
  5. Avoid common Octane pitfalls

    2.x

    When developing for Octane, avoid these frequent mistakes:

    • Container Resolution: Do not resolve config() or other container services in low-level worker boot code before the application is fully bootstrapped. Resolve them after the application is booted.
    • Authentication Leaks: Never capture Auth::user() in a singleton, static property, or custom guard binding. Always resolve authentication state per request.
    • Connection Accumulation: Manually close per-request Redis, database, or HTTP client connections opened outside of framework-managed pools. Use a RequestTerminated listener to reset them.
    • Superglobals: Do not use $_GET, $_POST, or $_SERVER. Use the Laravel Request object instead.
    • Serialization Errors: Do not capture non-serializable values (like PDO or Eloquent models) in concurrently() closures.
    • Worker Updates: Remember that code, environment variables, or configuration changes require a worker reload via octane:reload, a restart, or running with the --watch flag.
  6. Upgrade to Laravel Octane 2.0 from 1.x

    2.x

    To upgrade to Laravel Octane 2.0, ensure your environment meets the new minimum version requirements and update your application dependencies.

    Minimum Requirements:

    • PHP: v8.1.0 or higher
    • Laravel: v10.10.1 or higher

    Production Deployment Note: Before updating dependencies in a production environment, you must "stop" your Octane workers. You can restart the workers once the update is complete.

  7. Ensure state isolation in Octane

    2.x

    Because Octane reuses the application container across requests, storing request-specific data in singletons or static properties will cause state to leak between users.

    To prevent this:

    • Use $this->app->scoped() instead of $this->app->singleton() for services that hold data derived from the current request (e.g., Auth::user()).
    • Inject the Request object via method parameters or the request() helper rather than capturing it in a constructor.
    • Add services that hold per-request state to the flush list in config/octane.php.
    • Listen for the RequestTerminated event to manually reset any necessary static state.
    // Avoid: holds request 1's user for every later request
    $this->app->singleton(UserContext::class);
    
    // Prefer: flushed and re-resolved per request
    $this->app->scoped(UserContext::class);
  8. Update dependencies for Laravel Octane 2.0

    2.x

    Update your composer.json file to require the new versions of laravel/octane. If you are using the RoadRunner server, you must also update the spiral/roadrunner dependencies to the compatible versions.

    // Update Octane
    "laravel/octane": "^2.0"
    
    // If using RoadRunner, update these:
    "spiral/roadrunner-http": "^3.0.1",
    "spiral/roadrunner-cli": "^2.5.0"
  9. Use Swoole Tables and the Octane cache (Swoole only)

    2.x

    When using the swoole driver, you can utilize Swoole Tables and the octane cache store for high-performance, shared in-memory data.

    Swoole Tables:

    • Pre-sizing: You must pre-size tables at boot using the 'name:maxRows' syntax. Tables cannot be resized once created.
    • Volatility: Data in Swoole Tables is lost when workers restart; do not use them as a permanent database or Redis replacement.
    • Atomicity: Use incr() and decr() for atomic counters, as there are no transactions.

    Octane Cache:

    • Use the octane cache store only for ephemeral, high-frequency data. It shares memory with the workers and is not durable.
  10. Run tasks concurrently with Swoole

    2.x

    If using the swoole driver, you can execute closures in parallel using Octane::concurrently().

    Important Constraints:

    • Serialization: Closures are serialized for task workers. Do not capture $this or non-serializable objects (like PDO connections or Eloquent models). Instead, pass scalar IDs and re-fetch the models inside the closure.
    • Order: Results are returned in the same order as the input array.
    • Error Handling: Catch exceptions inside the closures if you need to transform or log them before Octane rethrows them.
    [$users, $orders] = Octane::concurrently([
        fn () => User::all(),
        fn () => Order::pending()->get(),
    ]);
  11. Configure static file serving in Swoole

    2.x

    When using the Swoole driver, Octane can serve static files directly from your public directory. To enable or configure this, use the serve_static_files and static_file_headers keys within your Octane configuration.

    • serve_static_files: A boolean to enable/disable static file serving.
    • static_file_headers: An associative array where keys are URL patterns (e.g., *.css) and values are arrays of headers to apply to those files.

    Note: Files with extensions like php, htaccess, or config are excluded from static serving for security.