Laravel Octane
repository·2.x·Indexed 26 days ago
https://github.com/laravel/octaneA 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.
What's inside Laravel Octane
- 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.
Test Octane applications correctly
2.xWhen 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').
- Simulate Request Lifecycle: Call
Detect the active Octane driver
2.xBefore using driver-specific features like concurrency or Swoole Tables, determine which server is running by checking the
octane.serverconfiguration key. This prevents errors when running on drivers like RoadRunner or FrankenPHP that do not support Swoole-specific APIs.Supported drivers are:
swoole,roadrunner, orfrankenphp.config('octane.server')Manage memory and prevent leaks in long-running workers
2.xSince workers are long-lived, unreferenced objects will accumulate and eventually crash the worker. Follow these practices to manage memory:
- Set Recycle Limits: Configure
max-requestsormax-jobsas 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
flushlist. - Watch Closures: Be cautious of singletons that capture large objects (like Eloquent models) within closures, as these will be held in memory forever.
- Set Recycle Limits: Configure
Avoid common Octane pitfalls
2.xWhen 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
RequestTerminatedlistener to reset them. - Superglobals: Do not use
$_GET,$_POST, or$_SERVER. Use the LaravelRequestobject instead. - Serialization Errors: Do not capture non-serializable values (like
PDOor Eloquent models) inconcurrently()closures. - Worker Updates: Remember that code, environment variables, or configuration changes require a worker reload via
octane:reload, a restart, or running with the--watchflag.
- Container Resolution: Do not resolve
Upgrade to Laravel Octane 2.0 from 1.x
2.xTo 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.0or higher - Laravel:
v10.10.1or 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.
- PHP:
Ensure state isolation in Octane
2.xBecause 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
Requestobject via method parameters or therequest()helper rather than capturing it in a constructor. - Add services that hold per-request state to the
flushlist inconfig/octane.php. - Listen for the
RequestTerminatedevent 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);- Use
Update dependencies for Laravel Octane 2.0
2.xUpdate your
composer.jsonfile to require the new versions oflaravel/octane. If you are using the RoadRunner server, you must also update thespiral/roadrunnerdependencies 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"Use Swoole Tables and the Octane cache (Swoole only)
2.xWhen using the
swooledriver, you can utilize Swoole Tables and theoctanecache 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()anddecr()for atomic counters, as there are no transactions.
Octane Cache:
- Use the
octanecache store only for ephemeral, high-frequency data. It shares memory with the workers and is not durable.
- Pre-sizing: You must pre-size tables at boot using the
Run tasks concurrently with Swoole
2.xIf using the
swooledriver, you can execute closures in parallel usingOctane::concurrently().Important Constraints:
- Serialization: Closures are serialized for task workers. Do not capture
$thisor non-serializable objects (likePDOconnections 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(), ]);- Serialization: Closures are serialized for task workers. Do not capture
Configure static file serving in Swoole
2.xWhen using the Swoole driver, Octane can serve static files directly from your
publicdirectory. To enable or configure this, use theserve_static_filesandstatic_file_headerskeys 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, orconfigare excluded from static serving for security.Supported Application Servers for Laravel Octane
2.xLaravel Octane supports the following high-performance application servers:
- FrankenPHP
- Open Swoole
- Swoole
- RoadRunner