Conversation
… already ended
cancel_job and cancel_run kill the active generator's subprocess so
inference stops at once, but they did so whatever the job's status. For
a job that had already finished, failed or been cancelled, that
subprocess belongs to whatever is generating now, or holds the warm
model: cancelling a finished job (the CLI's `legacy cancel` /
`workflow-run cancel`, or pressing Cancel as a generation completes)
failed the other generation with "Subprocess died during generation" or
forced the next one to reload the model from scratch.
Only kill the subprocess when the job being cancelled was still pending
or running; cancelling an ended job keeps returning {"cancelled": true}.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
Question: Im curious as if this also has an effect of the ability to free memory after a cancel/kill. Has anyone experience python separation from Modly processes when doing this? If so, that could be tied into this kind of fix. |
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
Cancelling a generation job that has already ended still kills the model worker:
Subprocess died during generation.This is easy to hit from the headless surface:
python tools/modly-cli/agent.py legacy cancel <job_id>orworkflow-run cancel <run_id>on a job that finished, failed, or was already cancelled. It also happens in the app when Cancel is pressed just as a generation completes, because the poll loop posts the cancel on its next tick, after the backend has marked the jobdone.Why it triggers
cancel_job(/generate/cancel/{id}) and its siblingcancel_run(/workflow-runs/{id}/cancel) only update the status while the job is pending or running. The subprocess kill after that runs unconditionally:ExtensionProcesskeeps its subprocess alive between generations to hold the loaded model, sogen._proc.poll() is Noneis true for an idle worker too. For an ended job, that subprocess isn't running the job being cancelled.Fix
In both endpoints, return before the kill when the job has already ended. Cancelling a pending or running job is unchanged. The response stays
{"cancelled": true}in every case, so clients see no difference.Verification
New
CancelEndedJobTestsinapi/tests/test_workflow_runs_lifecycle.py, next to the existingcancel_runtest. The registry's active worker is a fake with a live_proc.test_cancelling_a_finished_job_leaves_the_active_worker_alone(cancel_job, statusdone): fails before, passes after.test_cancelling_a_failed_run_leaves_the_active_worker_alone(cancel_run, statuserror): fails before, passes after.test_cancelling_a_running_job_still_stops_the_workerandtest_cancelling_a_running_run_still_stops_the_worker: pass before and after. A running job is still markedcancelled, and its worker is still killed, detached and marked unloaded. That proves the change doesn't widen into leaving a real cancellation running.The ended-job tests also assert the job's status is unchanged (
done/error), which holds before and after.Fail-before output, with the two routers reverted and the test kept. It is verbatim except that the local checkout path prefix is replaced with
<repo>, and the registry's import-time path banner that follows it is omitted:After the fix,
python -m unittest tests.test_workflow_runs_lifecyclepasses all 6 tests (Ran 6 tests in 0.021s/OK).Whole suite,
python -m unittest discover -s testsinapi/(venv withfastapi+python-multipart+httpx):devRan 93 tests/OK (skipped=3)Ran 97 tests/OK (skipped=3)test_workflow_runs_lifecycle.pyThe 3 skips were already there on
dev.Lint: the repo configures no Python linter, and ESLint ignores
api/**. As a spot check,ruff check --isolatedreports the same counts ondevand this branch:generation.py10 → 10,workflow_runs.py8 → 8,test_workflow_runs_lifecycle.py4 → 4, so nothing new. No TypeScript touched.🤖 Generated with Claude Code