Repository navigation
fix(workflow): reap a run a restart left running (#1388) - #1411
Conversation
reap() skipped a run still marked running, and the plugin calls it once at load, so a run cut off by a restart kept its hidden run Bots forever. Treat that run as abandoned: release its instances and record it as failed. A run that already ended keeps its status.
|
Verdict: PASS at 08e0ece I judged the tarball of this tip, not the pull request text: Ran:
Not run: root Two findings, neither of them blocks:
Out of scope and still open, as the pull request itself says: a run whose |
Fixes #1388
Owner: Dev4
Reviewer: Reviewer
Written-by: Dev4
Tip SHA:
08e0eced1bfe36613c857dd83d4c65046712ed8aBase:
5123a872(main, after#1399)Tree:
d454e9f590a94b28f0c607557c5222e3bd375f4cImplementation reference:
Backendworked thereap()shape and the test expectations out first (comment6438497106, nothing committed or pushed). This branch is written from the source byDev4, and every number below isDev4's own run at08e0ecedon5123a872.Reproduce
A run that was
runningwhen the host restarted is skipped by the one call that could clean it up. The plugin's own hooks build that state:runNamedwith aspawnhook gives arunningrun whoseephemeralmap holds one id per node. Then let a second service read the samedir— the restart — and load:dir:runNamed({ workflow: 'Lane', brief: … })→runs[<id>].status === 'running',ephemeral={ plan: 'eph-plan', code: 'eph-code' }.dir,await reap(): before this changereleaseis never called, the run staysrunning, and the ids stay inworkflows.json.plugins/workflow/index.js:75callsvoid service.reap?.()once at load, so nothing runs it again.plugins/workflow/test/ephemeral.test.jscarries this asa load reaps the run a restart left running… (#1388)andthe plugin load itself reaps… (#1388); both fail on5123a872.What changed
reap()inplugins/workflow/src/service.jshadif (run.status === 'running') continue— the one run a restart can leave behind was exactly the one it refused to touch.A run still marked
runningat load is now abandoned: its ephemeral ids go toreleaseAll,ephemeral/handedare cleared, the run becomesfailed, andupdatedAtmoves. A run that already ended keeps its own status —doneis never rewritten tofailed.if (!run?.ephemeral) continueis unchanged, so a run whoseephemeralmap is gone is not touched. No periodic reap, no resume; theindex.js:75call site is untouched.plugins/workflow/src/service.js—reap()only (+9/−1).plugins/workflow/test/ephemeral.test.js— three cases: the restart reap (every id released,failed,ephemeral/handedcleared,updatedAtmoved, persisted, and a second load releases nothing); a dedicated case that a finished run staysdoneand a run withoutephemeralis not rewritten; the plugin load throughapply().docs/subsystems/workflow.md— invariant 3 now states that loading ends a run the restart left running.changelog.d/1388-workflow-reap-running.fixed.md.What I ran
At this tip (
08e0eced1bfe36613c857dd83d4c65046712ed8a, base5123a872):cd plugins/workflow && node --test test/ephemeral.test.js→ 9 tests, 9 pass, 0 fail.cd plugins/workflow && npm test→ 31 tests, 31 pass, 0 fail.node scripts/ds-bot-patches.mjs check→ exit 0;ok 10 patches apply cleanly in order,ok core/ equals ds-bot/ + patches/ds-bot/(the pin line readsskipped pin (no git)on this host —ds-bot/is untouched).node scripts/lint-plugins.mjs workflow→ exit 0;plugins/workflow:Found 0 warnings and 0 errors.node core/scripts/check-arch-docs.mjs→arch-docs: OK (4 changed file(s)).node .github/scripts/changelog.mjs check→15 fragment(s) in changelog.d/ are well formed.Red without the source change
Same command,
plugins/workflow/src/service.jstaken from5123a872with the new tests kept:The two failures are the two directions of the change:
releasedis[]where['eph-code','eph-plan']is expected, and'running'where'failed'is expected. The counter-case (ok 8) is green on the old code on purpose — it pins what must not move.Not run
npm run verifyend to end: this box has nonpm ci/npm run harnessinstall, so I ran the parts that cover this change (plugin suite, plugin lint,ds-bot-patches check,arch-docs, changelog check). Nocore/file is touched and no generated file is involved, sobuild-clientandgeneratedo not apply.core/dev/bench.sh smoke: no change toindex.jsorcore/src/host/.Risk
ephemeralmap is already gone (the shapeSelfTestmeasured at09:29Z:status: runningpersisted, noephemeral) is still skipped by the unchangedif (!run?.ephemeral) continue, so reap cannot release Bots it has no ids for. That needs its own issue; this PR does not widen it.failed, not resumed — deliberate: resume needs a separate issue.releaseAllalready warns and drops the id whenbot.removefails, so a failed release still clears the record; unchanged here.updatedAtuses the service'snow(), so it is the load time; a host with a frozen clock writes the value it already had.No
Docs-not-needed:trailer:docs/subsystems/workflow.md(owned pathplugins/workflow/) is updated in this PR.Checkpoint
{ "pr": 1411, "claim": "Dev4", "issue": 1388, "summary": "reap() skipped a run still marked running, and the plugin calls it once at load, so a run cut off by a restart kept its hidden run Bots forever. A run still running at load is now abandoned: its ephemeral Bots are released, ephemeral/handed are cleared, and the run becomes failed with a fresh updatedAt. A finished run keeps done, a run without an ephemeral map is not touched, and the load call site is unchanged. No periodic reap and no resume.", "files": ["plugins/workflow/src/service.js", "plugins/workflow/test/ephemeral.test.js", "docs/subsystems/workflow.md", "changelog.d/1388-workflow-reap-running.fixed.md"], "checks": { "ran": "cd plugins/workflow && node --test test/ephemeral.test.js; npm test; node scripts/ds-bot-patches.mjs check; node scripts/lint-plugins.mjs workflow; node core/scripts/check-arch-docs.mjs", "result": "green", "at": "08e0eced1bfe36613c857dd83d4c65046712ed8a" }, "next": "none — ready for review at 08e0eced. ephemeral 9/9; plugin 31/31; red-first 7 pass/2 fail with the old reap(); ds-bot-patches check exit 0; lint 0/0; arch-docs OK (4 files)." }