Stuck-job detection has no reaping path — alerts re-raise forever and cancel is a no-op on orphaned jobs #56
Reference in New Issue
Block a user
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?
Summary
#41's detector correctly identifies jobs stuck in
running, but there is no way for an operator to clear them. Resolving the alert does not change the job row, so the detector re-raises on its next sweep; andPOST /api/jobs/{id}/cancelcannot help because it dispatches to an agent that no longer has the job.The result is an alert count permanently pinned at a non-zero number, with the only remedy being direct SQL against the server database.
Observed
A fleet accumulated 144 jobs in
runningdating back three months, from mixed causes (an agent panic since fixed, and older network failures reaching the restic REST store). After #41 shipped, all of them surfaced asjob_stuckalerts at once.Resolving them via the UI route succeeds, and the count drops to zero:
About one minute later, 143 alerts reappear — same underlying job IDs, new
CreatedAt, andLastSeenAtadvancing on each sweep. That is correct behaviour for the detector: those jobs are stillrunning, so they are still stuck. But it means alert resolution is a no-op against a persistent condition.Attempting the obvious remedy:
The job remains
status: runningindefinitely. Cancellation is delivered to the owning agent, and for a job orphaned months ago there is no agent-side process to cancel — the agent has restarted many times since. The 202 is misleading: it reports acceptance of a request that can never complete.Why this matters
cancelleddirectly resolved it here, but that is not something most operators should be doing on a backup orchestrator's database, and it is not documented anywhere.Suggested fix
Give stuck jobs a terminal state. Options, roughly in order of preference:
runningjob whosestarted_atpredates the owning agent's current connection (or whose host has since reconnected/restarted), transition it tocancelled/abandonedwith a reason. An agent that has reconnected demonstrably is not still running that job, which makes this safe to decide server-side without agent cooperation.POST /api/jobs/{id}/abandon, plus a bulk variant or a UI control on the alerts page, that sets the terminal state server-side without involving the agent.cancelfall back. If the target agent does not acknowledge within a timeout, or is not currently connected, mark the job terminal server-side rather than leaving itrunningafter a 202.Option 1 alone would have prevented the spike entirely, since every one of the 144 jobs belonged to a host that had reconnected many times since.
A migration that reaps pre-existing orphans on upgrade would also be worth considering, so existing deployments do not inherit the backlog.
Note on the alert semantics
Worth deciding explicitly whether
job_stuckalerts should be auto-resolved when the underlying job reaches a terminal state. Currently they must be resolved manually even after the cause is gone — after the DB fix above, the 143 alerts still had to be resolved by hand before the count returned to zero and stayed there.Environment
v1.2.1, agentv1.2.1