Skip to content

CPalius CMF 2.2.16

Released: 2026-09-25 · Channel: stable · Critical: yes

2.2.15 fixed the ordering between migrations and one specific cache clear. It wasn't enough, because the same class of problem had a second door: Symfony dispatches its own framework-level events — kernel.response, kernel.terminate — automatically, on every request, after a controller returns, whether or not any application code asked for that. Any module-owned listener on those events that hadn't been used yet in the request could still reach for a container file that had already been deleted a moment earlier by the same request. This release removes the door entirely instead of locking it more carefully.

What was actually wrong, this time correctly

Every part of this codebase that clears the compiled container has always deferred the actual deletion to kernel.terminate — a registered PHP shutdown function meant to run only after the response is fully sent. That was the right design. The mistake was a second, separate code path that could still force that same deletion to happen immediately, mid-request, specifically so a newly-spawned subprocess (compiling front-end assets) would see fresh files instead of stale ones.

Forcing it early solved that one subprocess's problem and created a bigger one: the request that forced it still had its own remaining work ahead — a redirect, a render, and always, unconditionally, Symfony's own kernel.terminate event dispatch — all of it now running with the container's files gone. 2.2.11 through 2.2.15 each made what happens after a purge faster and safer. None of them addressed that a purge could still happen mid-request at all, through this second path, regardless of how carefully everything else was sequenced around it.

What's fixed

The forced, mid-request purge path is gone. Every clearing of the compiled container — a full update, a patch, AACP's cache-rebuild screen, a theme activation, anything — now works exactly one way: scheduled, deferred, and only ever executed after kernel.terminate has already run to completion for that request, exactly as originally intended. Front-end asset compilation, which used to be the reason for forcing an early purge, now happens as part of that same deferred, background sequence instead of needing one.

The practical effect: the request that clears the cache always finishes normally, using the container it already had, regardless of what runs after it — including framework internals this codebase has no way to intercept or reorder around. Nothing after a cache clear can trip over a container that's still in the process of clearing.

Upgrade notes

No schema changes. No manual steps. Rebuilding after a clear now happens in the background rather than before the triggering request's response is returned — a cache-rebuild action (manual or automatic) reports "scheduled" immediately rather than waiting for the rebuild itself; the container and assets are ready by the time the next request arrives.

Last updated: 13.10.2026