Worker Mode¶
Available from version 4.7.0
Important
Worker Mode is currently experimental. The only officially supported worker implementation is FrankenPHP, which is backed by the PHP Foundation.
Introduction¶
What is Worker Mode?¶
Worker Mode is a performance optimization feature that allows CodeIgniter to handle multiple HTTP requests within the same bootstrapped application. PHP-FPM also reuses worker processes, but normally initializes and tears down the application for each request.
Traditional PHP vs Worker Mode¶
Traditional PHP (PHP-FPM)
In traditional PHP, each HTTP request goes through this cycle:
- Web server receives the request and passes it to an available PHP-FPM worker process
- PHP loads the required files, using cached bytecode when OPcache is enabled
- Framework bootstraps: autoloader, configuration, services, routes
- Database connections are established
- Request is processed and response is sent
- Request resources are released, including non-persistent connections
- Application state is torn down, and the worker process can handle another request
This "shared nothing" architecture is simple and safe, but inefficient for high-traffic applications because steps 2-4 repeat for every single request.
Worker Mode
In Worker Mode, the lifecycle changes dramatically:
- Worker process starts and performs one-time initialization:
- Loads and parses all required files (cached in OPcache)
- Bootstraps framework: autoloader, configuration, services, routes
- Establishes database and cache connections
- For each incoming request:
- Reuses existing connections and cached resources
- Resets only request-specific state (superglobals, request/response objects)
- Processes request and sends response
- Cleans up request-specific data
- Worker continues running, ready for the next request
This approach eliminates redundant initialization work and connection overhead, resulting in 2-3x performance improvements for typical database-driven applications.
How CodeIgniter Manages State¶
The key challenge in Worker Mode is preventing state from leaking between requests. CodeIgniter handles this through several mechanisms:
Services Reset
Most services are destroyed and recreated for each request. Only services listed in $persistentServices survive between requests.
Factories Reset
All Factories (Models, Config instances) are reset between requests, ensuring fresh instances without stale data.
Superglobals Isolation
Request data ($_GET, $_POST, $_SERVER, etc.) is properly isolated per request through the Superglobals service.
Connection Persistence
Database and cache connections are validated at request start and reused if healthy. Unhealthy connections are automatically re-established.
Getting Started¶
Installation¶
-
Install FrankenPHP following the official documentation
You can use a static binary or Docker. Here, we assume a static binary, which can be downloaded directly.
-
Install the Worker Mode template files using the spark command:
php spark worker:installThis command creates two files:
- Caddyfile - FrankenPHP configuration file with worker mode enabled
- public/frankenphp-worker.php - Worker entry point that handles the request loop
-
Configure your worker settings in app/Config/WorkerMode.php if needed. The defaults are recommended for most applications.
Note
When changing the project directory, see the section Renaming or Relocating the Application Directory and update your public/frankenphp-worker.php.
Running the Worker¶
Start FrankenPHP using the generated Caddyfile:
frankenphp run
The server will start with worker mode enabled, handling requests through the worker entry point.
To run in the background (daemon mode):
frankenphp start
Uninstalling¶
To remove the Worker Mode template files:
php spark worker:uninstall
This removes the Caddyfile and public/frankenphp-worker.php files.
Performance Benchmarks¶
Worker Mode typically provides 2-3x performance improvements for database-driven applications. The actual gains depend on your application's characteristics:
| Scenario | Expected Improvement |
|---|---|
| Simple endpoints | Applications returning minimal JSON responses show modest improvements (10-30%), as there's little bootstrap overhead to eliminate. |
| Database queries | Endpoints performing database queries typically see 2-3x improvements from connection reuse and reduced initialization overhead. |
| Complex bootstrap | Applications with many services, routes, or configuration see the largest gains, as this overhead is eliminated entirely. |
Worker Count Considerations¶
Total throughput scales with worker count. Match worker count to your typical concurrency patterns and available CPU cores. Too few workers limit concurrency; too many waste memory.
First Request Latency¶
The initial request to each worker is slower due to bootstrap and connection establishment. Subsequent requests benefit from cached resources and persistent connections.
Configuration¶
All worker mode configuration is managed through the app/Config/WorkerMode.php file.
Configuration Options¶
| Option | Type | Description |
|---|---|---|
| $persistentServices | array | Services that persist across requests and are not reset. Services not in this list are destroyed after each request to prevent state leakage. Default: ['autoloader', 'locator', 'exceptions', 'commands', 'codeigniter', 'superglobals', 'routes', 'cache'] |
| $resetEventListeners | array | Event names whose listeners are removed between requests. Use this when you register event listeners inside other event callbacks rather than at the top level of Config/Events.php, which would cause them to accumulate across requests. Default: [] |
| $forceGarbageCollection | bool | Whether to force garbage collection after each request. true (default, recommended): Prevents memory leaks. false: Relies on PHP's automatic garbage collection. |
Persistent Services¶
The $persistentServices array controls which services survive between requests. The default configuration includes:
| Service | Purpose |
|---|---|
autoloader |
PSR-4 autoloading configuration. Safe to persist as class maps don't change. |
locator |
File locator for finding framework files. Caches file paths for performance. |
exceptions |
Exception handler. Stateless, safe to reuse. |
commands |
CLI commands registry. Only used during worker startup. |
codeigniter |
Main application instance. Orchestrates the request/response cycle. |
superglobals |
Superglobals wrapper. Properly isolated per request internally. |
routes |
Router configuration. Route definitions don't change between requests. |
cache |
Cache service. Maintains connections to cache backends (Redis, Memcached). |
Warning
Adding services to $persistentServices without understanding their state management can cause data leakage between requests. Only persist services that are truly stateless or manage their own request isolation.
Reset Event Listeners¶
Available from version 4.7.1
Event listeners registered at the top level of Config/Events.php are loaded once at worker startup and persist correctly across requests. However, if you register a listener inside another event's callback, it will be re-registered on every request and accumulate:
<?php
use CodeIgniter\Events\Events;
// This runs every request — the 'my_event' listener stacks up indefinitely
Events::on('pre_system', static function (): void {
Events::on('my_event', 'MyClass::myMethod');
});
To clean up such listeners between requests, add the event name to $resetEventListeners in app/Config/WorkerMode.php:
<?php
namespace Config;
class WorkerMode extends \CodeIgniter\Config\WorkerMode
{
public array $resetEventListeners = ['my_event'];
}
Note
The recommended approach is to register listeners at the top level of Config/Events.php instead of inside callbacks. Use $resetEventListeners only when registering inside a callback is unavoidable.
Optimize Configuration¶
The app/Config/Optimize.php configuration options (Config Caching and File Locator Caching) should NOT be used with Worker Mode.
These optimizations were designed for traditional PHP where each request starts fresh. In Worker Mode, the persistent process already provides these benefits naturally, and enabling them can cause issues with stale data.
Warning
Do not enable $configCacheEnabled or $locatorCacheEnabled in app/Config/Optimize.php when using Worker Mode.
OPcache Settings¶
Worker Mode benefits significantly from OPcache. Ensure it's enabled and properly configured:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; In production only
Important Considerations¶
State Management¶
Since the PHP process persists across requests, careful attention to state management is essential:
- Avoid static properties for request-specific data, as these persist between requests
- Be cautious with singletons that might retain request state
- Clean up resources like file handles and database cursors after each request
- Don't store user data in class properties that persist across requests
Registrars¶
Config registrars (Config/Registrar.php files) work correctly in Worker Mode. Registrar files are discovered once when the worker starts, and registrar logic is applied every time a Config class is instantiated. Each request gets a fresh Config instance with registrars applied.
Memory Management¶
Monitor memory usage:
ps aux | grep frankenphp
If memory grows continuously:
- Verify garbage collection is enabled (
$forceGarbageCollection = true) - Ensure resources are properly closed after use
- Unset large objects when no longer needed
- Check for circular references that prevent garbage collection
Debugging¶
Worker Mode can make debugging more challenging since the process persists across requests:
- Restart workers after code changes - workers don't auto-reload modified files
- Check logs in writable/logs/ for connection and state-related issues
- Use logging liberally to trace request flow across the persistent process
Session and Cache Handlers¶
File-based handlers may experience file locking contention between workers. For production environments, consider using:
- Redis or Memcached for sessions and cache
- These provide better concurrency and automatic connection persistence
Database Connections¶
Database connections are automatically managed:
- Connections persist across requests for performance
- Connections are validated at the start of each request
- Failed connections are automatically re-established
- Uncommitted transactions are automatically rolled back with a warning logged