manager: runner drop-out recovery tests + two recovery fixes (#36) #38
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
blocked
draft
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
s1d3sw1ped/jiggablend!38
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ash/runner-dropout-recovery-36"
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?
Closes #36
What
recoverStuckTaskstick body moved intorecoverStuckTasksOnce(now)so tests can run one tick. The ticker loop calls it withtime.Now(). No behavior change.internal/manager/recovery_test.go: temp SQLite DB plus the realnext-jobHTTP handler and job WebSocket handler (httptest + gorilla client). Runners poll, authenticate with the job token, sendtask_complete/runner_heartbeat, or drop the TCP connection without a close frame.TestDeadRunnerFrameIsRenderedAgain(2 subtests)RunnerHeartbeatTimeout: marked offline, frame back to pending withretry_count0 andrunner_failure_count1. The frame is then rendered by another runner, or by the same runner when it polls again. Job endscompletedwith every frame.TestTimedOutFrameIsRenderedAgainWithoutBurningRetriestimeout_secondsgoes back to pending withretry_countunchanged, even when it is already atmax_retries. A frame under its timeout is left alone, runners stay online, and the job completes.TestJobConnectionDropRequeuesFrameretry_count1 and "WebSocket connection lost". Job is not failed and not stuck running. Re-render completes the job.TestLateDropFromDeadRunnerLeavesReassignedFrameAlone(2 subtests)TestJobConnectionHeartbeatKeepsItsRunnerOnlineBugs the tests found (fixed here)
handleWSRunnerHeartbeatupdatedjobs.assigned_runner_id, which is whichever runner last picked up any frame of the job. A runner does not poll while it renders, so the WS heartbeat is the only thing keeping it online. With two or more runners on one job, the runner mid-frame got no credit, was declared dead after 90s, and lost its frame. It now credits the runner on the connection (from the job token).running, even after the tick had requeued it and another runner had picked it up. That burned a retry and reset the other runner's frame. It also deleted the new runner's connection entry, which shares thejob-X-task-Ykey. Cleanup now only removes its own map entry, and only fails the task whenrunner_idis still this runner.Both bug tests failed on
developbefore the fix (task reset to pending / retry burned). A mutation check that reverts only the map-entry guard fails the "after the new runner connects" subtest.Tests (jumpbox)
go test -race -shuffle=on ./internal/manager/: ok, 85 passing tests incl. subtests (7 new top-level/sub cases across 5 tests).go test ./...: 219 passing. The only failure isrunner/encodingTestIntegration_Encode_EXR_H264, because the jumpbox has no ffmpeg. CI has it.Not covered
last_heartbeat < ?compares Go-formatted timestamps as text. It is fine while the manager's zone offset is stable, but a DST change could shift the cutoff by an hour for one tick.GO from me.
The tick refactor is a straight move:
recoverStuckTasksOnce(now)has the same body, panic guard and order as the old closure, and the ticker just passestime.Now().Both fixes look right to me. The heartbeat now credits
claims.RunnerIDfrom the job token, and the socket only gets that far when the task'srunner_idmatches it, so the runner doing the render is the one kept online. The disconnect cleanup now drops only its own map entry and fails the task only whenrunner_idis still this runner, which stops a dead runner's late drop from resetting the next runner's frame or burning its retry.The tests drive the real next-job and job WebSocket handlers against a real DB, and you checked that the bug tests fail on develop and that the mutation check catches the map guard. That's good enough proof for me. The head sits on the develop tip (
5adfcea) and CI run 61 is green. The goimports whitespace changes are fine.This doesn't change auth, secrets, deps or CI, so it doesn't need Blake. Linus can merge.