fix(jobs): reconcile declared background jobs Nextcloud never registered (24 of 31 were missing) - #2172
Merged
Merged
Conversation
…gistered
Nextcloud writes oc_jobs only when an app is INSTALLED or UPGRADED. Add a <job>
to info.xml without bumping the app version and it is silently never registered
— no error, no warning, and there is no occ background-job:add to correct it.
Measured on a live instance: 24 of 31 declared jobs were absent. Not only flows —
scheduled workflows, schedule reconciliation, sync, webhook retries, notification
flushing, archival retention and DBAL introspection were all inert. 59 flow runs
sat queued and could never execute.
It hides well: the synchronous counterparts keep working. POST /api/flow-runs/test
calls FlowRunService::execute() directly, so interactive flow testing was green
while every asynchronous trigger queued into a void, staying "queued" forever
rather than failing.
This repair step parses the <job> declarations out of info.xml and adds any that
IJobList does not already have. Because it is a repair step it runs on
occ maintenance:repair, so an instance can be corrected without inventing a
version bump. Idempotent, and one unresolvable job is logged and skipped rather
than aborting the run — the point of the step is to recover an instance.
Two traps this hit while being written, both worth knowing:
1. SimpleXML cannot reach a hyphenated element as $xml->background_jobs; it
needs $xml->{'background-jobs'}. The mismatch returns nothing rather than
erroring.
2. simplexml_load_file() SILENTLY RETURNS FALSE inside the Nextcloud runtime.
NC installs a restrictive libxml external-entity loader at boot, and PHP 8
routes file access through it. The same parse works in a bare php -r process
and fails under require lib/base.php — so the step reported "no <job>
declarations found" against an info.xml holding 31 of them. Fixed by reading
the file and parsing a string. Any app code parsing XML by path is suspect
for the same reason.
Verified by controlled experiment on a live instance: deleted FlowScheduleWorker
from oc_jobs, ran the step, and it reported "Registered missing background job:
OCA\OpenRegister\Cron\FlowScheduleWorker / 1 added, 0 skipped, 31 declared" with
the row restored. Separately, a version bump plus occ upgrade took the instance
from 9 to 34 distinct registered job classes.
Refs or#2170.
Contributor
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 555/555 | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Quality workflow — 2026-07-27 20:47 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2170.
The problem
Nextcloud writes
oc_jobsonly when an app is installed or upgraded. Add a<job>toinfo.xmlwithout bumping the app version and it is silently never registered — no error, no warning, and there is noocc background-job:addto correct it by hand.Measured on a live instance: 24 of 31 declared jobs were absent. Not only flows — scheduled workflows, schedule reconciliation, sync, webhook retries, notification flushing, archival retention and DBAL introspection were all inert, with 59 flow runs sitting
queuedthat could never execute.It hides well, because the synchronous counterparts keep working.
POST /api/flow-runs/testcallsFlowRunService::execute()directly, so interactive flow testing was green while every asynchronous trigger queued into a void — stayingqueuedforever rather than failing.The fix
A repair step that parses the
<job>declarations out ofinfo.xmland adds anyIJobListdoes not already have. Being a repair step, it runs onocc maintenance:repair, so an instance can be corrected without inventing a version bump. Idempotent; one unresolvable job is logged and skipped rather than aborting the run, since the whole point is to recover an instance.Verified by controlled experiment
Deleted a registered job, ran the step, watched it come back:
Separately, a version bump plus
occ upgradetook the instance from 9 to 34 distinct registered job classes.Two traps hit while writing this, both worth knowing
1. SimpleXML cannot reach a hyphenated element as
$xml->background_jobs— it needs$xml->{'background-jobs'}. The mismatch returns nothing rather than erroring.2.
simplexml_load_file()silently returns false inside the Nextcloud runtime. NC installs a restrictive libxml external-entity loader at boot, and PHP 8 routes file access through it. The identical parse works in a barephp -rprocess and fails underrequire lib/base.php— so the step reported "no declarations found" against an info.xml holding 31 of them. Fixed by reading the file and parsing a string.That second one generalises: any app code parsing XML by path is suspect for the same reason.
🤖 Generated with Claude Code