feat: move unified generation to background worker
This commit is contained in:
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta, timezone
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import desc, select
|
||||
from sqlalchemy import desc, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
@@ -59,6 +59,7 @@ def _job_progress(job: GenerationJob) -> dict[str, Any]:
|
||||
|
||||
progress_map: dict[str, tuple[int, str]] = {
|
||||
"request_accepted": (5, "已接收请求"),
|
||||
"worker_started": (12, "后台任务已开始"),
|
||||
"context_prepared": (20, "上下文已准备"),
|
||||
"narrative_generated": (45, "正文已生成"),
|
||||
"story_saved": (60, "主记录已保存"),
|
||||
@@ -66,8 +67,18 @@ def _job_progress(job: GenerationJob) -> dict[str, Any]:
|
||||
"provider_call_succeeded": (72, "Provider 调用成功"),
|
||||
"provider_call_failed": (72, "Provider 调用失败,尝试恢复"),
|
||||
"cover_image_started": (75, "封面生成中"),
|
||||
"cover_image_succeeded": (88, "封面已生成"),
|
||||
"cover_image_failed": (88, "封面生成失败"),
|
||||
"storybook_images_started": (75, "绘本插图生成中"),
|
||||
"storybook_cover_image_succeeded": (82, "绘本封面已生成"),
|
||||
"storybook_cover_image_failed": (82, "绘本封面生成失败"),
|
||||
"storybook_page_image_succeeded": (86, "分页插图已生成"),
|
||||
"storybook_page_image_failed": (86, "分页插图生成失败"),
|
||||
"storybook_images_completed": (92, "绘本插图已完成"),
|
||||
"audio_started": (75, "音频生成中"),
|
||||
"audio_cache_hit": (88, "音频缓存已复用"),
|
||||
"audio_succeeded": (88, "音频已生成"),
|
||||
"audio_failed": (88, "音频生成失败"),
|
||||
"asset_retry_started": (25, "资源重试中"),
|
||||
"postprocessing_queued": (90, "后处理已排队"),
|
||||
"asset_generation_completed": (100, "资源已完成"),
|
||||
@@ -155,6 +166,10 @@ async def record_generation_event(
|
||||
) -> GenerationJobEvent:
|
||||
"""Append one event to an existing generation job."""
|
||||
|
||||
job.current_step = event_type
|
||||
if story_id is not None:
|
||||
job.story_id = story_id
|
||||
|
||||
event = GenerationJobEvent(
|
||||
job_id=job.id,
|
||||
story_id=story_id if story_id is not None else job.story_id,
|
||||
@@ -169,6 +184,42 @@ async def record_generation_event(
|
||||
return event
|
||||
|
||||
|
||||
async def claim_generation_job_for_worker(
|
||||
db: AsyncSession,
|
||||
*,
|
||||
job_id: str,
|
||||
) -> GenerationJob | None:
|
||||
"""Claim one queued generation job for worker execution once."""
|
||||
|
||||
claim_result = await db.execute(
|
||||
update(GenerationJob)
|
||||
.where(
|
||||
GenerationJob.id == job_id,
|
||||
GenerationJob.status == "running",
|
||||
GenerationJob.current_step == "request_accepted",
|
||||
)
|
||||
.values(current_step="worker_started")
|
||||
)
|
||||
await db.commit()
|
||||
|
||||
if not claim_result.rowcount:
|
||||
return None
|
||||
|
||||
result = await db.execute(select(GenerationJob).where(GenerationJob.id == job_id))
|
||||
job = result.scalar_one_or_none()
|
||||
if job is None:
|
||||
return None
|
||||
|
||||
await record_generation_event(
|
||||
db,
|
||||
job=job,
|
||||
event_type="worker_started",
|
||||
status="running",
|
||||
message="Generation worker started processing the accepted request.",
|
||||
)
|
||||
return job
|
||||
|
||||
|
||||
async def finish_generation_job(
|
||||
db: AsyncSession,
|
||||
*,
|
||||
|
||||
Reference in New Issue
Block a user