Skip to content

fix(worker): keep FastAPI out of modules the workers import - #663

Merged
Valtora merged 2 commits into
mainfrom
fix/worker-backup-import
Oct 23, 2026
Merged

Valtora merged 2 commits into
mainfrom
fix/worker-backup-import

Conversation

@Valtora

@Valtora Valtora commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Pull Request

Description

The worker images install requirements/worker.txt, which has no FastAPI. backend/utils/document_storage.py imported HTTPException and run_in_threadpool from FastAPI at module level, and the restore runner, the restore stages and the storage hygiene scan all import it. On the workers that broke four tasks at their first import:

  • create_backup_task and restore_backup_task, through backend.core.backup
  • cleanup_backup_artifacts, the six-hourly backup cleanup
  • cleanup_temp_recordings, the daily cleanup, which imported storage hygiene on its first line, so none of its sweeps ran either

CI installs the API and worker requirements together, so no test saw it. The chain arrived with #495 and #533 on 21 Oct. No release has it.

What changed:

  • document_storage raises RecordingGoneError when an upload's recording is deleted under it, and documents.py turns it into the same 404 Recording not found. That covers the upload endpoint and create_text_document, which the MCP attach_document tool calls. The file cleanup's thread hop calls anyio.to_thread.run_sync, which is all FastAPI's run_in_threadpool does, so the thread limiter and the cancellation behaviour are unchanged. test_document_storage_cancellation.py still covers both.
  • cleanup_temp_recordings imports storage hygiene inside the guard that already catches a hygiene failure, so the sweeps before it run whatever happens to that import.
  • New backend/tests/test_worker_import_boundary.py. It walks every backend module a worker can reach: the Celery app and its include list, every module under backend/worker, the GPU preflight, the diarisation subprocess script and the storage hygiene command. It follows imports inside functions, since the tasks import their work lazily. It imports all of them in a subprocess with FastAPI, Starlette, uvicorn, mcp, docker, reportlab, re2 and their dependencies blocked by a meta-path finder, and fails on any unguarded import of those packages in a worker-reachable module, inside a function or out. A further test fails when a new pin in backend.txt alone is missing from the blocked list.
  • docs/DEVELOPMENT.md states the rule under the backend conventions and lists both image-boundary tests under Test Reliability.

No new dependencies. anyio is already in every image through httpx.

Fixes: #660

Decision record

  • Domain error, converted in the endpoint. DEVELOPMENT.md already says to raise HTTPException in endpoints. The other option was to move insert_document_or_remove_file and delete_document_files into the API layer, which would split one module's lifecycle rules, and its tests, across two places.
  • Not the calendar service's guard. calendar_service imports HTTPException inside try/except ModuleNotFoundError and sets it to None on the workers. That would have passed here too, but a worker path that ever reached the raise would fail with a TypeError.
  • Left as they are: calendar_service/__init__.py, oauth.py, sync.py and dashboard.py keep that guard. They import cleanly on the workers, and their raises are in API-only helpers. The new test allows a guarded import.
  • What the test models: the base worker image. worker-io carries Starlette, uvicorn and mcp through claude-agent-sdk, but worker-cpu runs the backups and has none of them. pyannote.audio is installed by the Dockerfile and not in CI, so a module that needs it is skipped by the import check and still read by the static check.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behaviour)
  • Documentation update

Checks run

  • Python: scripts/check.py lint format blindexcept heldpins typecheck docs alembic and the full pytest suite with a pgvector Postgres, in nojoin-dev-tests:local: 3618 passed. Whitespace, file size and validate_docs.py on the host.
  • Frontend: not touched.
  • Site: not touched.
  • Docs only: not applicable.

The two new tests fail on main and pass here. On main the import check fails 13 modules, backend.core.backup among them, all with No module named 'fastapi'. The hygiene test fails because the task raises before its sweeps.

Migration impact

  • No database migration.

Documentation impact

  • No documentation change required.
  • Updated the guide that owns each changed behaviour, setup, deployment or support topic (.github/CONTRIBUTING.md, "Documentation Ownership").

Security impact

  • No security-sensitive change.

Manual verification

Imported every module a worker can reach (256, all 21 task modules among them) and backend.core.backup in throwaway containers on the locally built nojoin-worker and nojoin-worker-io images, which have no FastAPI. This branch's backend/ was mounted read-only, with no network and no .env. Both images import everything with no failures. With main's backend/ the same check fails the 13 modules above on both images.

Valtora and others added 2 commits October 23, 2026 17:48
The worker images install no FastAPI, and document_storage imported it,
so backups, restores, the backup cleanup and the daily temp cleanup failed
on the workers. It now raises RecordingGoneError, which the documents
endpoint turns into the same 404. The daily cleanup imports storage
hygiene inside its guard, so a failed import no longer skips the sweeps.

Fixes: #660
@Valtora
Valtora merged commit 40f7500 into main Oct 23, 2026
21 checks passed
@Valtora
Valtora deleted the fix/worker-backup-import branch October 23, 2026 18:11
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.

Backups and restores fail on the workers: No module named 'fastapi'

1 participant