Raw provider crash fails the job instead of escaping into the sweep requeue loop

A non-AIError from transcribe/summarize (av.InvalidDataError on corrupt
audio, seen live with 'My recording 63') escaped the consumer, left the
row 'running', and got requeued at every engine restart forever. Both
runners now catch it, fail the row with the exception type in the
message, and keep a usable transcript (summarize completes with a
'Summary failed' note). Regression tests pin both paths (proven red
without the fix).
This commit is contained in:
avi 2026-09-19 15:24:50 -05:00
commit 514d75fe92
2 changed files with 73 additions and 0 deletions

View file

@ -251,6 +251,45 @@ async def test_config_error_fails_fast(client, monkeypatch):
assert stt.calls == 1
async def test_raw_provider_crash_fails_job_no_escape(client, monkeypatch):
"""A non-AIError from the provider (e.g. av.InvalidDataError on corrupt
audio) must FAIL the row, not escape: an escaping exception leaves the
job 'running' and the startup sweep requeues it forever."""
stt = FakeTranscriber(fail=ValueError("Invalid data found when processing input"))
use_fakes(monkeypatch, stt, FakeLlm())
token = await user_tokens(client)
rec = await upload_recording(client, token, client_id="m7-crash-1")
await processing.run_transcribe({"job_try": 1}, rec["id"]) # must NOT raise
jobs = await jobs_for(rec["id"])
assert jobs[JobType.transcribe].status == JobStatus.failed
assert "ValueError" in (jobs[JobType.transcribe].error or "")
h = {"Authorization": f"Bearer {token}"}
r = await client.get(f"/api/v1/recordings/{rec['id']}", headers=h)
assert r.json()["processing_status"] == "failed"
async def test_raw_summarize_crash_keeps_transcript(client, monkeypatch):
use_fakes(monkeypatch, FakeTranscriber("fine text"), FakeLlm())
token = await user_tokens(client)
rec = await upload_recording(client, token, client_id="m7-crash-2")
await processing.run_transcribe({}, rec["id"])
class ExplodingLlm(FakeLlm):
async def summarize(self, transcript, **kw):
raise RuntimeError("llm segfaulted")
use_fakes(monkeypatch, FakeTranscriber("fine text"), ExplodingLlm())
await processing.run_summarize({"job_try": 1}, rec["id"]) # must NOT raise
jobs = await jobs_for(rec["id"])
assert jobs[JobType.summarize].status == JobStatus.failed
h = {"Authorization": f"Bearer {token}"}
r = await client.get(f"/api/v1/recordings/{rec['id']}", headers=h)
body = r.json()
# Transcript survived: recording completes with a summary-failure note.
assert body["processing_status"] == "completed"
assert "Summary failed" in body["processing_error"]
# --- versioning -----------------------------------------------------------------