rig forgejo-runner status reports (active) as health — a poller that has gone quiet looks identical to a working runner
#133
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:bootstrap
scope:coolify
scope:db
scope:docs
scope:drill
scope:installer
scope:labels
scope:platform
scope:runner
scope:users
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/rig#133
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
rig forgejo-runner statusreports a runner as healthy when it may be doing nothing at all, and the service unit cannot notice either.Measured on 2026-07-30 while probing a real runner against
forgejo.heavyduty.builders(8.0.3+gitea-1.22.0, runnerv12.13.2), for #129:23:15:05, logged[poller] launched, and never fetched a job dispatched four minutes later. The run sat plainly visible in the web UI as "job is not started".systemctl is-activewould have saidactive.23:19:46claimed the queued task at23:19:47— one second — and the job finished two seconds after that.I hit the same thing twice in one session, and both times it looked exactly like a label-mapping bug on the Forgejo side. Nothing rig ships would have told an operator otherwise.
Why this is rig's, not upstream's
Two surfaces rig owns both assert the wrong thing:
commands/forgejo-runner-status.sh:72—STATE="$(systemctl is-active forgejo-runner)", printed asservice: forgejo-runner.service (active). The command's own header (:25) states its contract: "Reads only the runner's own on-disk config — no token, no network call." Soactiveis the strongest health signal it has, andactiveproves only that a process exists.commands/forgejo-runner-install.sh:456— the unit carriesRestart=on-failure. A quiet poller is not a failure: nothing exits, nothing returns non-zero, so systemd never restarts it.This is the bug class rig already names as its own.
commands/bootstrap.sh(the box-install block) puts it directly:service: (active)is exactly asserting what was requested. Andforgejo-runner-status.sh:85already says this file is the right place for precisely this kind of catch:A poller that has gone quiet is a mode that drifted.
What is NOT claimed here
The cause is not established and this issue does not need it to be. It was observed on a NAT'd box and may be an idle long-poll drop that never occurs on a real ci-box. That is fine: the defect being filed is that rig cannot tell the difference, which is true whatever the cause and whatever the frequency.
Also not claimed: that
rig forgejo-runner statusshould make a network call. It should not, without a deliberate decision — see the ruling below.Spec
Make
statusstop presentingactiveas proof of work, in the one place an operator looks when nothing is obviously wrong.Decided:
statusprints an informational line saying whatactivedoes and does not prove, and names the remedy and the symptom to match against.WARNING:on every run would be crying wolf.warnin this file is reserved for a drift that has actually been detected (:89, the.runnermode check).:25stands; this change must not break it, andtest/cli.sh:3392already guards the token half.Deliberately out of scope, because it is a product decision rather than a repair: making the daemon self-heal.
Restart=alwaysplus a boundedRuntimeMaxSecwould recycle a stalled poller automatically, but the runner's ownshutdown_timeoutdefaults to3h, so a recycle can kill an in-flight job. Trading a silent stall for a killed build is @andres's call, not a builder's. If it is wanted, it is a second issue.Tasks
commands/forgejo-runner-status.sh, emitted only when the unit exists and is activesystemctl restart forgejo-runner, then re-read) so the line is actionable rather than a disclaimertest/cli.sh's forgejo-runner block: the line is present, it is not aWARNING:, and the no-network-call contract still holdschangelog.d/<n>.mdAcceptance criteria
statusoutput tells the reader thatactiveis not proof the runner is fetchingWARNING:— the existingwarnsemantics in this file are unchangedstatusstill makes no network call and reads no token —test/cli.sh:3392's guard still passesbash test/cli.shpasses; CI'sshellcheck -xstep is cleanchangelog.d/<n>.mdrecords the behaviour changeTest plan
test/cli.sh's existing forgejo-runner block, driven — not grepped where behaviour can be executed:warninstead oflogand the not-a-warning check goes red.grep -q 'json_field .* token',:3392) still passes, and nocurl/wgetappears in the file.Dependencies
heavy-duty/rig.@andres — filed at your request.
needs-triagebecause I am not triage; I am claiming and building it immediately, so treat the queue label as bookkeeping you can correct.Note I did not file the second finding I mentioned (the deprecated
registersubcommand). Reason in a comment below — rig already decided that one on purpose, and I was wrong to call it a finding.Why I did not file the
register-is-deprecated finding@andres — you asked for both findings filed. I am filing one and declining the other, because I checked and I was wrong to call it a finding.
commands/forgejo-runner-install.sh:376-395already carries the whole thing — the measurement, the decision, and the migration plan:with three stated reasons, and then:
I re-verified the load-bearing reason rather than taking the comment's word for it.
forgejo-runner daemon --helpon v12.13.2:The successor still needs a UUID that must already exist on the instance, and the config-file form (
connections:withurl+uuid+token) needs the same.create-runner-file, the only other way to get one, is also marked deprecated. So there is no non-deprecated path to a UUID today — exactly what the comment says, still true on the version rig's own "latest" resolution installs.Filing an issue would re-litigate a documented decision on identical evidence, which REVIEWER.md is explicit is not a reviewer's move. The correct trigger is upstream removing
register, and the code already says what to do then.The only thing my probe adds is a stronger corroboration than the comment claims for itself: it says a planted
.runnergot as far as"Unauthenticated: unregistered runner", whereas I ran a real registration and a real job to completion on v12.13.2. That strengthens the existing note; it does not change the decision. Not worth an issue, and I have not edited the comment either — it is accurate as written.If you want it tracked anyway as a watch item, say so and I will file it as one, plainly labelled as tracking-not-buildable.
Post-merge verification —
86b7498/306844d, both clean@andres — verified on merged
mainrather than carrying the pre-merge runs forward.main9afcdf85(!130) and848e3f42(!134) are both ancestors — nothing rewritten at mergeshellcheckstep, incl. the coverage guardtest/drill.shtest/release.shtest/install-lifecycle.shforgejo_leg_row+forgejo_max_task_idindrill/drill.sh;forgejo_runner_liveness_noteinforgejo-runner-status.shtest/cli.shreads 785 / 13 on mergedmain. All 13 are #136's environmental failures — this box carries a real Forgejo runner, soci-box's installer correctly early-exits andbootstrap --undocorrectly refuses. Unmodifiedmainscored the same 13 before any of these merges, and !137 is the fix; it is the last of the four still open and now the only thing standing between this suite and green on a drilled box.What is still open on the two issues these closed against
Both PRs carry
Refs, notCloses, so #129 and #133 stay open by design — their live-run acceptance criteria are #107/#115's exercise on real hardware, which needs the runner token only you can mint. That is the honest state, not an oversight.#129 also still carries the
needs-triage+claimedconflict from your 23:21:55 label. Unchanged and still yours to settle; I have not touched it.Closed by triage — delivered via !134, acceptance criteria verified on
mainLabel events re-read before this write:
claimedset at mint (2026-07-31T00:02Z) by the claiming builder; no queue event since. The claim is not stale — it is finished: !134 merged intomain(head848e3f4, an ancestor of86b7498-eramain), referencing this issue withRefs, post-merge verified 2026-07-31.Verified against the acceptance criteria, on
mainatcb4de44, today:activegets a liveness noteforgejo-runner-status.sh:32—forgejo_runner_liveness_note, gated[ "${1:-}" = active ], called at:108warnlog, three lines; the file'swarnsemantics untouched (:117unchanged)activestate:52) stands; nocurl/wgetin the filechangelog.d/133.mdpresent, one line,### Fixedbash test/cli.sh's forgejo-runner block covers the note (the !134 round drove it; post-merge verification ran the suites green). Nothing on this issue awaits a builder or a release event — unlike #129, every criterion here is checkable onmain, so it closes now rather than sittingpost-merge.