Skip to content
Edit this page

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:

  1. Web server receives the request and passes it to an available PHP-FPM worker process
  2. PHP loads the required files, using cached bytecode when OPcache is enabled
  3. Framework bootstraps: autoloader, configuration, services, routes
  4. Database connections are established
  5. Request is processed and response is sent
  6. Request resources are released, including non-persistent connections
  7. 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:

  1. 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
  2. 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
  3. 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

  1. 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.

  2. Install the Worker Mode template files using the spark command:

    php spark worker:install
    

    This command creates two files:

    • Caddyfile - FrankenPHP configuration file with worker mode enabled
    • public/frankenphp-worker.php - Worker entry point that handles the request loop
  3. 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