v8.5.30
⚠️ Fix: two installs sharing an FPM pool shared their rollup counters
APCu belongs to the whole pool, and a pool can serve more than one install — prod
and test on one box, a handful of tenant vhosts, a staging site beside the live one.
Every key this accumulator wrote was ovos:console:rollups:… whatever the install,
so those installs shared all of it, in three ways of increasing severity:
- Counters summed across installs.
…:<minute>:r:/user/indexwas one bucket for
all of them, so one project's console got another's traffic as its own denominator. - One flush watermark. Whichever install crossed the minute boundary first
advancedflushed, and the other then treated its own unshipped minutes as done. - The same
(instance, seq). Both shipped under one identity, and the console
dedups retries by exactly that pair — so it dropped one of the two as a duplicate.
An additive counter never recovers from a fragment that was never added.
The namespace now comes from config, not from anything derived: cache.prefix
(typically !ENV CACHE[PREFIX]), the same value Cache\Perishable hands the APCu
store, joined onto PREFIX by the same Cache\Prefixer. Sender reads it
(Sender::cachePrefix()) and passes it in; the key constants became suffixes that
key() puts behind the prefix, and the APCUIterator pattern carries it too, so a
flush cannot even see another install's keys.
The identity needed the same treatment for a separate reason: separate keys give each
install its own seq counter, but the identity value is p<pid>-<base36 time> —
and one pool means one worker serving both installs, so the pid and the second can be
identical. A base36 crc32 of the key prefix goes in as a third segment, well inside
the console's [A-Za-z0-9._-]{1,64} identity shape (21 characters for a typical
prefix).
Inert where it does not apply: an install that configures no cache prefix keeps
exactly the keys it had. After the upgrade a pool mints a fresh instance, which is
the case the design already covers — an APCu restart looks the same to the console.
Verified against a real pool, which the unit tests leave alone by design: two installs
counting the same minute and the same route ship 3 and 7 requests under their own keys,
with distinct identities and no keys left behind. The suite adds
keysCarryTheInstallNamespace to Tests\Service\Console\Rollup.
The same fix landed in ovos/cms first; this is the port back to the original.