Skip to content

fix(model): serialise backend loading and refuse unload mid-generation - #572

Merged
remsky merged 2 commits into
remsky:masterfrom
davidcoulson:fix/backend-load-race
Oct 29, 2026
Merged

remsky merged 2 commits into
remsky:masterfrom
davidcoulson:fix/backend-load-race

Conversation

@davidcoulson

Copy link
Copy Markdown
Contributor

ensure_backend returned early whenever _backend was set, but initialize
sets it before load_model finishes, so after an idle unload a second
request could start generating on a half-loaded model. A failed load
also left that object in place, so later requests kept using it.
/dev/unload and /dev/reload took the lifecycle lock but ignored
_active_requests and could unload the model under a generator paused
between chunks.

Always take the lock in ensure_backend, clear _backend when loading
fails, and have unload and reload raise ModelBusyError while requests
are generating, which the dev routes return as 409.

Testing

  • pytest: full suite passes.
  • New tests in test_model_unload.py: a caller arriving mid-load waits for it, a failed load leaves no backend and the next call retries, and unload/reload refuse (and the routes 409) while a request is generating. The first four fail on master.
  • On an RTX 3070 (Unraid, nvidia runtime), image built from docker/gpu/Dockerfile.optimized with this and the sibling PRs merged with ALLOW_DEV_UNLOAD=true: /dev/unload during a long generation returns 409 and that generation completes; after an idle unload, three concurrent speech requests all return 200 with no errors in the log.

Follows #562-#568 from the same review. Based on master on its own; the only overlap with those PRs is the CHANGELOG [Unreleased] section.

davidcoulson and others added 2 commits October 28, 2026 16:36
ensure_backend returned early whenever _backend was set, but initialize
sets it before load_model finishes, so after an idle unload a second
request could start generating on a half-loaded model. A failed load
also left that object in place, so later requests kept using it.
/dev/unload and /dev/reload took the lifecycle lock but ignored
_active_requests and could unload the model under a generator paused
between chunks.

Always take the lock in ensure_backend, clear _backend when loading
fails, and have unload and reload raise ModelBusyError while requests
are generating, which the dev routes return as 409.
@remsky
remsky merged commit db3f70f into remsky:master Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants