Repository navigation
fix: a failed CLEAN run was reported as completed with no results - #161
Open
matthewberry wants to merge 2 commits into
Open
matthewberry wants to merge 2 commits into
matthewberry wants to merge 2 commits into
Conversation
The CLEAN command pipes the inference through `tee` into the job log, so without `set -o pipefail` the pipeline's status was tee's. A crash skipped the `error` sentinel, the job template touched `finished`, and the job was marked completed.
…tead With pipefail, a failed inference exited the `job` container non-zero. That container is an init container, so post-job never ran and the log (and `error`) never reached MinIO; the only record of the crash was on the shared volume. A failed inference now writes `error` and exits 0, so post-job uploads the outputs. postjob.py then exits 1 when `error` is present, which fails the Job and the watcher marks it 'error' as before. CRISPR-Copies and Mutagenesis still exit non-zero and are unchanged.
matthewberry
force-pushed
the
mjberry/fix/clean-pipefail
branch
from
November 5, 2026 15:36
599d052 to
829ea8d
Compare
matthewberry
changed the base branch from
main
to
mjberry/fix/postjob-exit-code
November 5, 2026 15:36
This was referenced Nov 5, 2026
matthewberry
added a commit
that referenced
this pull request
Nov 5, 2026
fetch_organism.py and convert_annotations.py run as the crispr-copies prejob_command in the backend's init container. A failure there failed that container, so the job container and post-job never ran and the traceback reached no one. - prejob_command now tees the setup scripts' output to `log` and touches `error` on failure, exiting 0 (in chart/values.yaml, app/cfg/config.yaml and local.config.yaml). - The CRISPR-Copies command skips the tool when `error` already exists, and appends to `log` (tee -a) so the setup output is kept on every path. - post-job then uploads `log` and `error`, and #161's check fails the Job. Tests run the rendered init container and then the job container, sharing one output directory: a failed fetch or convert keeps its traceback and skips the tool; a successful or failed tool run keeps the setup output too. Reverting either the prejob_command or the command fails four of them. A further test checks the chart's prejob_command matches app/cfg/config.yaml.
matthewberry
added a commit
that referenced
this pull request
Nov 5, 2026
…st-job `fail` Review on #171: checking `fail` in postjob.py applied it to every job type, though only the novostoic commands write it. The four commands now write `error`, which postjob.py already fails the Job on, so postjob.py is back to #161's version. The new test renders each novostoic command from the chart through the real job template, and builds the job type list from the chart.
matthewberry
added a commit
to moleculemaker/clean-frontend
that referenced
this pull request
Nov 5, 2026
…load getResponseResult() only logged an error from the results request, so contentLoaded stayed false and the loader spun forever. That happens for a completed CLEAN job with no _maxsep.csv: the backend's results endpoint answers 404. Jobs like that already exist (crashed runs that were marked completed before moleculemaker/mmli-backend#161). Set failedJob and contentLoaded in that error handler, as the status-polling error handler already does.
This was referenced Nov 5, 2026
Collaborator
Author
|
Review of 829ea8d. No blocking findings. Ran: Checked and cleared
Notes
|
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.
Stacked on #160. This changes
app/postjob.pyafter #160's upload handling, so merge #160 first. This PR's base then switches tomain.Problem
A CLEAN run that crashes is reported as
completed. The user gets a "ready" email, and the results page shows an error because there is no_maxsep.csv.The CLEAN command (
app/services/clean_service.py) runs:Without
pipefail, a pipeline's exit status is that of its last command,tee, which succeeds. So when the inference fails:|| touch $JOB_OUTPUT_DIR/errorfallback never runs;&& touch "${JOB_OUTPUT_DIR}/finished"(job.tpl.yaml) does run;jobcontainer exits 0,post-jobuploadsfinishedandlog, and the watcher marks the job completed.This happened to job
f289fd27…on 2026-11-04. Its log ends withRuntimeError: torch.cat(): expected a non-empty list of Tensors. It leftfinishedandlogin MinIO, with noerrorand no_maxsep.csv. (Why that run crashed is a separate question. It isn't addressed here.)CRISPR-Copies and Mutagenesis use the same
| tee logpattern and already setpipefail. A word search forteeacross the repo finds only these three commands, and CLEAN was the only one without it.Why the Job is failed in
post-job, not in thejobcontainerAdding
pipefailalone (this PR's first commit) makes thejobcontainer exit non-zero, but that loses the log:job.tpl.yaml,jobis an init container, andpost-job(postjob.py, which uploads the output directory) is the pod's main container;post-jobnever runs;errorandlogstay on the shared volume and never reach MinIO. Thef289fd27diagnosis above was only possible because its log was uploaded.So a failed inference writes
errorand exits 0 instead, andpost-jobfails the Job after uploading.Change
clean_service.py: prefix the command withset -o pipefail &&, and change the fallback from|| (touch error && false)to|| touch error. A failed inference now writeserrorand exits 0; the template then touchesfinished.postjob.py: after the upload, exit 1 if$JOB_OUTPUT_DIR/errorexists. WithrestartPolicy: NeverandbackoffLimit: 0, the Job fails; the watcher marks the joberrorand sends the "failed" email.error.jobcontainer (&& false), so their behavior is unchanged. Tools that never writeerrorare unaffected.error,finishedandlog. Nothing inapp/readsfinishedorerrorfrom MinIO (grepped), but I haven't checked the frontend.Deploy note
post-jobalways runsmoleculemaker/mmli-backend:main(hardcoded injob.tpl.yaml,imagePullPolicy: Always), whatever backend version created the Job. A backend running this branch's CLEAN command against a:mainimage without the newpostjob.pycheck would mark failed runscompleted. Don't deploy this branch to an environment before:maincontains thepostjob.pychange.Testing
tests/test_clean_job_exit_code.py:create_jobwith the realbuild_clean_job_commandoutput, astest_job_shm.pydoes. It then runs thejobinit container'sbash -cscript, with a stand-inpythononPATH.error,finishedandlog._maxsep.csv,finishedandlog(noerror).pipefail: both failure cases fail (noerror).tests/test_postjob_exit_code.py(from fix: exit non-zero when postjob fails to upload a job's outputs #160) gains one case: witherrorpresent, the upload runs and then the script exits 1. It fails with the check removed.Dockerfile.testimage: 630 passed.