Fix download status flapping: only the 'completed' event is terminal
Production logs showed a job oscillating downloading -> completed -> downloading -> completed -> postprocessing -> completed. Cause: yt-dlp reports status='finished' via progress-hook ticks once per stream when downloading separate video+audio for muxing (video lands, audio is still in flight), and MeTube forwards that through 'updated' Socket.IO events too -- we were mapping any status='finished' to our "completed", regardless of which event carried it. Only the dedicated 'completed' event (and the 'done' bucket of MeTube's /history, for startup reconciliation) is now treated as authoritative for terminal status; a transient 'finished' arriving via 'added'/'updated' (or history's queue/pending) is a no-op for status, matching the progress_percent update it also carries. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
fe16c08daa
commit
e333296170
2 changed files with 80 additions and 11 deletions
|
|
@ -138,6 +138,59 @@ async def test_handle_metube_event_completed_builds_media_url(monkeypatch, db_se
|
|||
assert job.completed_at is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_transient_finished_in_updated_event_does_not_complete_job(db_session):
|
||||
"""Regression test for a real bug seen in production logs: yt-dlp reports
|
||||
status='finished' via 'updated' events once per stream when merging
|
||||
separate video+audio (finished for video, then still downloading audio),
|
||||
which used to flip our job to 'completed' prematurely and then back to
|
||||
'downloading', flapping the UI. Only the dedicated 'completed' event may
|
||||
mark a job completed."""
|
||||
video = _seed_video(db_session)
|
||||
job = DownloadJob(video_id=video.id, status="downloading", metube_job_id="vid1.vid1", progress_percent=80)
|
||||
db_session.add(job)
|
||||
db_session.commit()
|
||||
|
||||
# video stream finished (transient) -- must NOT become "completed"
|
||||
await download_jobs.handle_metube_event(
|
||||
db_session,
|
||||
"updated",
|
||||
json.dumps({"id": "vid1.vid1", "url": video.youtube_url, "status": "finished"}),
|
||||
)
|
||||
db_session.refresh(job)
|
||||
assert job.status == "downloading"
|
||||
|
||||
# audio stream still downloading
|
||||
await download_jobs.handle_metube_event(
|
||||
db_session,
|
||||
"updated",
|
||||
json.dumps({"id": "vid1.vid1", "url": video.youtube_url, "status": "downloading", "percent": 10}),
|
||||
)
|
||||
db_session.refresh(job)
|
||||
assert job.status == "downloading"
|
||||
assert job.progress_percent == 10
|
||||
|
||||
# ffmpeg merge
|
||||
await download_jobs.handle_metube_event(
|
||||
db_session,
|
||||
"updated",
|
||||
json.dumps({"id": "vid1.vid1", "url": video.youtube_url, "status": "postprocessing"}),
|
||||
)
|
||||
db_session.refresh(job)
|
||||
assert job.status == "postprocessing"
|
||||
|
||||
# only the dedicated 'completed' event finalizes it
|
||||
await download_jobs.handle_metube_event(
|
||||
db_session,
|
||||
"completed",
|
||||
json.dumps(
|
||||
{"id": "vid1.vid1", "url": video.youtube_url, "status": "finished", "filename": "vid1.vid1.mp4"}
|
||||
),
|
||||
)
|
||||
db_session.refresh(job)
|
||||
assert job.status == "completed"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_metube_event_error_marks_failed(db_session):
|
||||
video = _seed_video(db_session)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue