Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/Config/WorkerMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ class WorkerMode
'cache',
];

/**
* Reset Event Listeners
*
* List of event names whose listeners should be removed between requests.
* Use this if 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 in worker mode.
*
* @var list<string>
*/
public array $resetEventListeners = [];

/**
* Force Garbage Collection
*
Expand Down
4 changes: 3 additions & 1 deletion system/Commands/Worker/Views/frankenphp-worker.php.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,10 @@ while (frankenphp_handle_request($handler)) {
// Reset services except persistent ones
Services::resetForWorkerMode($workerConfig);

// Reset event listeners
Events::cleanupForWorkerMode($workerConfig->resetEventListeners);

if (CI_DEBUG) {
Events::cleanupForWorkerMode();
Services::toolbar()->reset();
}
}
14 changes: 11 additions & 3 deletions system/Events/Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,18 @@ public static function getPerformanceLogs()
* Cleanup performance log and request-specific listeners for worker mode.
*
* Called at the END of each request to clean up state.
*
* @param list<string> $resetEventListeners Additional event names to reset.
*/
public static function cleanupForWorkerMode(): void
public static function cleanupForWorkerMode(array $resetEventListeners = []): void
{
static::$performanceLog = [];
static::removeAllListeners('DBQuery');
if (CI_DEBUG) {
static::$performanceLog = [];
static::removeAllListeners('DBQuery');
}

foreach ($resetEventListeners as $event) {
static::removeAllListeners($event);
}
}
}
9 changes: 9 additions & 0 deletions user_guide_src/source/changelogs/v4.7.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ Message Changes
Changes
*******

Events
======

- **Worker Mode:** :php:func:`Events::cleanupForWorkerMode()` now accepts an optional
``$resetEventListeners`` array parameter, corresponding to the new
``$resetEventListeners`` property in ``Config\WorkerMode``. This allows users to
declare event names that should be cleaned up between requests when listeners are
registered inside event callbacks. See :ref:`worker-mode-reset-event-listeners`.

Others
======

Expand Down
16 changes: 14 additions & 2 deletions user_guide_src/source/installation/upgrade_471.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ Please refer to the upgrade instructions corresponding to your installation meth
Mandatory File Changes
**********************

Worker Mode
===========

If you are using Worker Mode, you must update **public/frankenphp-worker.php** after
upgrading. The easiest way is to re-run the install command:

.. code-block:: console

php spark worker:install --force

****************
Breaking Changes
****************
Expand Down Expand Up @@ -44,12 +54,14 @@ and it is recommended that you merge the updated versions with your application:
Config
------

- @TODO
- app/Config/WorkerMode.php
- ``Config\WorkerMode::$resetEventListeners`` has been added, with a default
value set to ``[]``. See :ref:`worker-mode-reset-event-listeners` for details.

All Changes
===========

This is a list of all files in the **project space** that received changes;
many will be simple comments or formatting that have no effect on the runtime:

- @TODO
- app/Config/WorkerMode.php
27 changes: 27 additions & 0 deletions user_guide_src/source/installation/worker_mode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ Option Type Description
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.
Expand Down Expand Up @@ -214,6 +218,29 @@ Service Purpose
state management can cause data leakage between requests. Only persist services
that are truly stateless or manage their own request isolation.

.. _worker-mode-reset-event-listeners:

Reset Event Listeners
=====================

.. versionadded:: 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:

.. literalinclude:: worker_mode/001.php

To clean up such listeners between requests, add the event name to
``$resetEventListeners`` in **app/Config/WorkerMode.php**:

.. literalinclude:: worker_mode/002.php

.. 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
**********************
Expand Down
8 changes: 8 additions & 0 deletions user_guide_src/source/installation/worker_mode/001.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?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');
});
8 changes: 8 additions & 0 deletions user_guide_src/source/installation/worker_mode/002.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Config;

class WorkerMode extends \CodeIgniter\Config\WorkerMode
{
public array $resetEventListeners = ['my_event'];
}
Loading