Skip to content

[stable31] fix(loopback): circles:check always fails due to APCu race and missing CLI wrapper - #2990

Merged
cristianscheid merged 2 commits into
stable31from
backport/2387/stable31
Oct 5, 2026
Merged

cristianscheid merged 2 commits into
stable31from
backport/2387/stable31

Conversation

@backportbot

@backportbot backportbot Bot commented Oct 2, 2026

Copy link
Copy Markdown

Backport of PR #2387

i2h3 and others added 2 commits October 2, 2026 15:37
The `circles:check` loopback test always fails with a 401 on the POST
request to `asyncBroadcast` with `test-dummy-token` when the config key
`test_dummy_token` does not already exist in the database.

Root cause: The GET request to `core.CSRFToken.index` (which runs first)
causes the web server process to load all `appconfig` values into its
APCu local cache (TTL=3s). Only then does the CLI process insert
`test_dummy_token` into the database and clear its own APCu cache — but
CLI and web server run in separate SAPI contexts with independent APCu
stores, so the web cache is unaffected. When the POST request arrives
shortly after the GET (well within the 3-second TTL), the web process
reads from its still-valid APCu cache, which does not contain the newly
inserted key. `getValueInt()` therefore returns the default `0`, and
`0 < time()` evaluates to true, causing the controller to return 401.

Moving `setValueInt()` before the GET request ensures the key exists in
the database before any web request loads the appconfig into APCu.

Signed-Off-By: Iva Horn <iva.horn@nextcloud.com>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Even after the 401 is resolved, `circles:check` still fails with
"Event created too many Wrappers" (actually zero wrappers found, the
message is misleading). The LoopbackTest FederatedEvent never gets an
EventWrapper created when running from CLI.

Root cause: `initBroadcast()` has an early-return guard:

    if (empty($instances) && (!$event->isAsync() || OC::$CLI))

For a LoopbackTest event (which implements IFederatedItemAsyncProcess but
has no remote instances), `$instances` is empty. Combined with
`OC::$CLI === true`, the guard returns false — skipping all wrapper
creation. This optimisation is correct for regular async events in CLI
mode, where `newEvent()` already calls `manage()` synchronously and no
async broadcast is needed. However, the LoopbackTest specifically exists
to verify that the async loopback path works end-to-end: wrapper
creation, async POST, `manageWrapper()`, and `confirmStatus()` must all
run to produce the verify/manage values that `testLoopback()` asserts.

The fix exempts events whose class implements IFederatedItemLoopbackTest
from the CLI guard, so that a wrapper is created and the async broadcast
is triggered even when running from CLI. The double call to `manage()`
(once synchronously in `newEvent()`, once asynchronously via the
wrapper) is harmless for LoopbackTest since it only sets an idempotent
result value.

Signed-Off-By: Iva Horn <iva.horn@nextcloud.com>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cristianscheid
cristianscheid merged commit 16a9f08 into stable31 Oct 5, 2026
34 of 35 checks passed
@cristianscheid
cristianscheid deleted the backport/2387/stable31 branch October 5, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants