Worker Mode
New in 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 PHP process, instead of starting a new process for each request like traditional PHP-FPM does.
Traditional PHP vs Worker Mode
Traditional PHP (PHP-FPM)
In traditional PHP, each HTTP request goes through this cycle:
Web server receives request and spawns a new PHP process
PHP loads and parses all required files
Framework bootstraps: autoloader, configuration, services, routes
Database connections are established
Request is processed and response is sent
All connections are closed
PHP process terminates, freeing all memory
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
$persistentServicessurvive 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 will assume we use 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.
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: |
$forceGarbageCollection |
bool |
Whether to force garbage collection after each request.
|
Persistent Services
The $persistentServices array controls which services survive between requests.
The default configuration includes:
Service |
Purpose |
|---|---|
|
PSR-4 autoloading configuration. Safe to persist as class maps don’t change. |
|
File locator for finding framework files. Caches file paths for performance. |
|
Exception handler. Stateless, safe to reuse. |
|
CLI commands registry. Only used during worker startup. |
|
Main application instance. Orchestrates the request/response cycle. |
|
Superglobals wrapper. Properly isolated per request internally. |
|
Router configuration. Route definitions don’t change between requests. |
|
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.
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