Skip to content

v8.5.30

Choose a tag to compare

@marcing marcing released this 17 Sep 20:21
· 3 commits to main since this release
29d7916

⚠️ 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:

  1. Counters summed across installs. …:<minute>:r:/user/index was one bucket for
    all of them, so one project's console got another's traffic as its own denominator.
  2. One flush watermark. Whichever install crossed the minute boundary first
    advanced flushed, and the other then treated its own unshipped minutes as done.
  3. 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.