Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions backend/api/v1/endpoints/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from backend.processing.documents import SUPPORTED_EXTENSIONS
from backend.services.recording_identity_service import get_recording_by_public_id
from backend.utils.document_storage import (
RecordingGoneError,
delete_document_files,
insert_document_or_remove_file,
)
Expand Down Expand Up @@ -59,6 +60,14 @@ async def _get_owned_recording(
return recording


async def _insert_document(db: AsyncSession, document: Document) -> None:
"""Insert a new document's row, answering 404 if its recording went meanwhile."""
try:
await insert_document_or_remove_file(db, document, logger=logger)
except RecordingGoneError as error:
raise HTTPException(status_code=404, detail="Recording not found") from error


# Configuration for documents storage. Resolved through PathManager so it tracks
# NOJOIN_DATA_DIR rather than the process working directory.
DOCUMENTS_DIR = str(PathManager().documents_directory)
Expand Down Expand Up @@ -96,7 +105,7 @@ async def create_text_document(
status=DocumentStatus.PENDING,
parse_mode=DocumentParseMode.STRUCTURAL,
)
await insert_document_or_remove_file(db, document, logger=logger)
await _insert_document(db, document)
await db.commit()
await db.refresh(document)

Expand Down Expand Up @@ -294,7 +303,7 @@ async def upload_document( # noqa: PLR0913 - FastAPI dependencies are parameter
DocumentParseMode.VISUAL if deep_parse else DocumentParseMode.STRUCTURAL
),
)
await insert_document_or_remove_file(db, document, logger=logger)
await _insert_document(db, document)
await db.commit()
await db.refresh(document)

Expand Down
28 changes: 28 additions & 0 deletions backend/tests/test_storage_hygiene_entrypoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import logging
import os
import sys
import tempfile
import uuid
from collections.abc import Iterator
Expand Down Expand Up @@ -446,3 +447,30 @@ def no_database():
]
assert len(failure) == 1
assert failure[0].exc_info is not None


def test_a_hygiene_module_that_fails_to_load_does_not_stop_the_daily_cleanup(
layout: Layout,
daily_mode: str,
monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture,
) -> None:
"""The sweeps before hygiene must still run when its import fails.

#660 put a FastAPI import on the hygiene path, which the worker images do
not install. The task imported hygiene on its first line, so it failed
before any sweep ran.
"""
monkeypatch.setitem(sys.modules, "backend.utils.storage_hygiene", None)
stale = write_file(layout.recordings / "failed" / "1_failed_x.wav", age_hours=72)

with caplog.at_level(logging.ERROR):
system_tasks.cleanup_temp_recordings.run()

assert not stale.exists(), daily_mode
failure = [
r for r in caplog.records if r.getMessage().startswith("Storage hygiene failed")
]
assert len(failure) == 1
assert failure[0].exc_info is not None
assert isinstance(failure[0].exc_info[1], ImportError)
Loading
Loading