Fix parallel catchup hanging on orphaned in-progress jobs - #434
Merged
Conversation
Claiming a job and registering its owner were two separate redis calls; if the second failed the job sat in the progress queue with no owner, which the monitor cannot detect because it derives its worker set from the owners hash. Claim atomically, requeue unowned jobs, and fail the mission if it stalls.
Contributor
There was a problem hiding this comment.
Pull request overview
Hardens parallel catchup recovery and stall handling to prevent indefinitely hung builds.
Changes:
- Adds atomic job claiming and orphan recovery.
- Introduces Redis timeouts and idempotent completion.
- Adds mission stall detection and configurable monitor images.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Review |
|---|---|
src/MissionParallelCatchup/parallel_catchup_helm/values.yaml |
Configures the monitor image. |
src/MissionParallelCatchup/parallel_catchup_helm/templates/job_monitor.yaml |
Uses the configured monitor image. |
src/MissionParallelCatchup/parallel_catchup_helm/files/worker.sh |
Completion is not ownership-safe. |
src/MissionParallelCatchup/job_monitor.py |
Orphan requeue operations are not atomic. |
src/FSLibrary/MissionHistoryPubnetParallelCatchupV2.fs |
Stall detection excludes queued work; two minor wording issues remain. |
Suppressed comments (4)
src/FSLibrary/MissionHistoryPubnetParallelCatchupV2.fs:457
- The failure message is inaccurate when
monitorNotAdvancingalone triggers the timeout: the last status can still report live workers. Name both failure conditions so operators know whether worker liveness or the monitor heartbeat caused the abort.
failwith "Catch up stalled, no progress and no live workers"
src/FSLibrary/MissionHistoryPubnetParallelCatchupV2.fs:435
- Use “unable to update” to correct the grammar in this comment.
// itself gets stuck unable to updating its internal metrics and
src/MissionParallelCatchup/job_monitor.py:170
- This detects only jobs with no hash entry, not jobs whose recorded owner is dead. With jobs owned by pods A and B, if A is down but B responds, the later
workers_up == 0gate skips all retries, so A's job remains in progress forever; the mission-side aggregate liveness check is also masked by B. Confirm liveness per owner and requeue only the jobs belonging to owners that remain down.
# --- Phase 1b: Requeue orphaned jobs (in progress, but owned by nobody) ---
orphans = [job for job in jobs_in_progress if job not in job_owners]
for job in orphans:
logger.error("Requeuing orphaned job %s: in %s with no owner in %s",
job, PROGRESS_QUEUE, JOB_OWNERS)
requeue_job(job)
src/MissionParallelCatchup/parallel_catchup_helm/files/worker.sh:125
- A nonempty invalid value has already been moved into
PROGRESS_QUEUEand registered inJOB_OWNERSby the claim script. This branch only logs and sleeps, so that entry remains owned but is never processed or completed; the orphan detector will not recover it because its owner exists. Atomically remove the claim and either place the malformed item in the failed set or terminate it according to the desired invalid-job policy.
elif [ -n "$JOB_KEY" ]; then
echo "Error: Unexpected claim reply, not a job key: $JOB_KEY"
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Jonathan-Eid
approved these changes
Sep 4, 2026
sisuresh
approved these changes
Sep 4, 2026
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.
what
why
A recent parallel catchup build hung due to a stale state (has job in progress but no worker working). Claiming a job and recording its owner were two separate steps, so a transient Redis failure in between left a job that no worker was running and that nothing in the system could recognize as stuck.
This removes the gap that loses the job, gives the monitor a way to recover if it happens anyway, and makes any future variant fail quickly.