fix(music-lab): pipeline 동기 작업을 asyncio.to_thread로 — 이벤트 루프 블로킹 해결
video.generate/thumb.generate/youtube.upload_video는 동기 함수로 ffmpeg subprocess(최대 5분)와 google-api-python-client(최대 10분)를 호출함. async run_step에서 직접 호출하면 이벤트 루프가 블로킹돼 후속 요청이 504로 타임아웃되고 텔레그램 폴링도 끊김. asyncio.to_thread로 감싸 스레드 풀에서 실행 — 이벤트 루프 자유.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
"""파이프라인 오케스트레이터 — 단계별 BackgroundTask 등록 및 산출물 → DB 반영."""
|
"""파이프라인 오케스트레이터 — 단계별 BackgroundTask 등록 및 산출물 → DB 반영."""
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -106,7 +107,8 @@ async def _run_video(p, track):
|
|||||||
vd = setup["visual_defaults"]
|
vd = setup["visual_defaults"]
|
||||||
audio_path = track.get("file_path") or _local_path(track.get("audio_url", ""))
|
audio_path = track.get("file_path") or _local_path(track.get("audio_url", ""))
|
||||||
cover_path = _local_path(p["cover_url"])
|
cover_path = _local_path(p["cover_url"])
|
||||||
out = video.generate(
|
out = await asyncio.to_thread(
|
||||||
|
video.generate,
|
||||||
pipeline_id=p["id"], audio_path=audio_path, cover_path=cover_path,
|
pipeline_id=p["id"], audio_path=audio_path, cover_path=cover_path,
|
||||||
genre=track.get("genre", "default"),
|
genre=track.get("genre", "default"),
|
||||||
duration_sec=track.get("duration_sec", 120),
|
duration_sec=track.get("duration_sec", 120),
|
||||||
@@ -117,8 +119,11 @@ async def _run_video(p, track):
|
|||||||
|
|
||||||
async def _run_thumb(p, track, feedback):
|
async def _run_thumb(p, track, feedback):
|
||||||
video_path = _local_path(p["video_url"])
|
video_path = _local_path(p["video_url"])
|
||||||
out = thumb.generate(pipeline_id=p["id"], video_path=video_path,
|
out = await asyncio.to_thread(
|
||||||
track_title=track.get("title", ""), overlay_text=True)
|
thumb.generate,
|
||||||
|
pipeline_id=p["id"], video_path=video_path,
|
||||||
|
track_title=track.get("title", ""), overlay_text=True,
|
||||||
|
)
|
||||||
return {"next_state": "thumb_pending", "fields": {"thumbnail_url": out["url"]}}
|
return {"next_state": "thumb_pending", "fields": {"thumbnail_url": out["url"]}}
|
||||||
|
|
||||||
|
|
||||||
@@ -152,7 +157,8 @@ async def _run_publish(p, track):
|
|||||||
setup = db.get_youtube_setup()
|
setup = db.get_youtube_setup()
|
||||||
meta = json.loads(p["metadata_json"]) if p.get("metadata_json") else {}
|
meta = json.loads(p["metadata_json"]) if p.get("metadata_json") else {}
|
||||||
privacy = setup["publish_policy"].get("privacy", "private")
|
privacy = setup["publish_policy"].get("privacy", "private")
|
||||||
result = youtube.upload_video(
|
result = await asyncio.to_thread(
|
||||||
|
youtube.upload_video,
|
||||||
video_path=_local_path(p["video_url"]),
|
video_path=_local_path(p["video_url"]),
|
||||||
thumbnail_path=_local_path(p["thumbnail_url"]) if p.get("thumbnail_url") else None,
|
thumbnail_path=_local_path(p["thumbnail_url"]) if p.get("thumbnail_url") else None,
|
||||||
metadata=meta, privacy=privacy,
|
metadata=meta, privacy=privacy,
|
||||||
|
|||||||
Reference in New Issue
Block a user