Persist RunPod job id and reattach to in-flight jobs after a daemon interruption - #136
Open
quevon24 wants to merge 8 commits into
Open
Conversation
6 tasks
quevon24
force-pushed
the
127-persist-runpod-job-id-resume-in-flight-jobs-after-a-daemon-interruption
branch
from
July 22, 2026 01:52
e22663b to
12e5ee4
Compare
grossir
self-requested a review
July 24, 2026 19:43
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.
Closes #127.
Problem
When the daemon is killed mid-pipeline (SIGTERM on deploy/eviction, SIGKILL/OOM) or a scan times out, the in-flight scan is re-queued and the pipeline re-runs. The RunPod
job_idlived only as a local variable insiderunpod_client._submit/_poll, so on restart the daemon couldn't tell a job was already running. Two costs, both seen live on scan 1940 (2026-07-20): the killed daemon never cancelled the in-flight job (only the timeout path did), so it ran orphaned for 57m until cancelled by hand, while the re-queue submitted a duplicate job that ran concurrently; and detect/OCR was redone from scratch even when the previous job had finished.Fix
Persist the RunPod job handle on the
Scanand, on re-entry, reattach to the existing job instead of submitting a duplicate.runpod_job_id/runpod_job_action/runpod_job_submitted_atfields._invokerecords the id after submit and clears it on any terminal outcome; on a hard kill it stays set, so the next tick reattaches: a COMPLETED job's result is reused (GPU step skipped), an IN_QUEUE/IN_PROGRESS job is picked up without duplicating. A job aged out of RunPod's retention window returns 404, which the existing_pollpath turns into a re-queue that submits fresh, so recovery is always safe.ERROR_INTERRUPTEDare terminal and will never reattach, so their jobs are cancelled to stop billing and their persisted handle is cleared (so a later re-queue or a frontend re-detect/revalidate submits fresh rather than reattaching a dead job). Re-queued scans keep their handle so they still reattach.Follow-ons in this PR
RUNPOD_REQUEST_TIMEOUT + RUNPOD_REQUEST_TIMEOUT_PER_PAGE * page_count), so a large volume (e.g. 1300 pages x 3 detect models) no longer false-times-out against a flat base. A genuine timeout stays terminal with no auto-retry._recover_staleuses a per-scan threshold ofmax(DAEMON_PROCESSING_TIMEOUT, 2x the page-aware ceiling)instead of a single global timeout, so raising the request timeout can't leave stale recovery cutting off a large scan whose job is still legitimately running._run_yolopushesdetections.jsonto S3 the moment detection finishes, andrun_full_pipelineskips detection when it already exists (restored from S3 on a resume), mirroring the existing OCR-PDF guard. So an interruption during a later stage no longer redoes detection.Notes on behavior
interruption_count; the interruption still happened and the cap is about daemon churn, not job outcome.Testing
DEVELOPMENT=True DB_HOST=localhost DB_SSL_MODE=prefer python manage.py test scanning.tests— 353 tests pass. New coverage: persist/clear/reattach across every/statusstate,cancel_job, page-aware timeout, aligned stale cutoff, detect stage-skip and S3 persist, cancel-only-flagged on shutdown with handle clearing, and the error banner.