feat: move unified generation to background worker
This commit is contained in:
@@ -12,7 +12,7 @@ from sqlalchemy.orm import joinedload
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.logging import get_logger
|
||||
from app.db.models import ChildProfile, Story, StoryUniverse
|
||||
from app.db.models import ChildProfile, GenerationJob, Story, StoryUniverse
|
||||
from app.schemas.story_schemas import (
|
||||
AchievementItem,
|
||||
FullStoryResponse,
|
||||
@@ -33,6 +33,7 @@ from app.services.audio_storage import (
|
||||
write_story_audio_cache,
|
||||
)
|
||||
from app.services.generation_jobs import (
|
||||
claim_generation_job_for_worker,
|
||||
create_generation_job,
|
||||
ensure_no_active_story_generation_job,
|
||||
finish_generation_job,
|
||||
@@ -1113,7 +1114,7 @@ async def generate_generation_service(
|
||||
user_id: str,
|
||||
db: AsyncSession,
|
||||
) -> GenerationResponse:
|
||||
"""Unified generation workflow entry point for stories and storybooks."""
|
||||
"""Queue one unified generation workflow for background execution."""
|
||||
|
||||
job = await create_generation_job(
|
||||
db,
|
||||
@@ -1124,7 +1125,65 @@ async def generate_generation_service(
|
||||
)
|
||||
|
||||
try:
|
||||
response = await _generate_generation_service_with_job(request, user_id, db, job=job)
|
||||
from app.tasks.generation_workflow import run_generation_workflow_task
|
||||
|
||||
run_generation_workflow_task.delay(job.id)
|
||||
except Exception as exc:
|
||||
await finish_generation_job(
|
||||
db,
|
||||
job=job,
|
||||
story=None,
|
||||
status="failed",
|
||||
current_step="generation_failed",
|
||||
error_message="Background generation dispatch failed.",
|
||||
message="Generation failed before the worker could start processing the job.",
|
||||
metadata={"dispatch_error": str(exc)},
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="后台生成任务派发失败,请确认 worker 可用后重试。",
|
||||
) from exc
|
||||
|
||||
return _build_queued_generation_response(request, job_id=job.id)
|
||||
|
||||
|
||||
def _build_queued_generation_response(
|
||||
request: GenerationRequest,
|
||||
*,
|
||||
job_id: str,
|
||||
) -> GenerationResponse:
|
||||
"""Build the immediate API response after a generation job is accepted."""
|
||||
|
||||
return GenerationResponse(
|
||||
id=None,
|
||||
generation_job_id=job_id,
|
||||
title="生成任务已提交",
|
||||
mode="storybook" if request.output_mode == "storybook" else "generated",
|
||||
generation_status="queued",
|
||||
text_status="generating",
|
||||
image_status="not_requested",
|
||||
audio_status="not_requested",
|
||||
last_error=None,
|
||||
retryable_assets=[],
|
||||
child_profile_id=request.child_profile_id,
|
||||
universe_id=request.universe_id,
|
||||
)
|
||||
|
||||
|
||||
async def execute_generation_job_service(
|
||||
job: GenerationJob,
|
||||
db: AsyncSession,
|
||||
) -> GenerationResponse:
|
||||
"""Execute one previously accepted generation job inside the worker."""
|
||||
|
||||
try:
|
||||
request = GenerationRequest.model_validate(job.request_payload or {})
|
||||
response = await _generate_generation_service_with_job(
|
||||
request,
|
||||
job.user_id,
|
||||
db,
|
||||
job=job,
|
||||
)
|
||||
except HTTPException as exc:
|
||||
await finish_generation_job(
|
||||
db,
|
||||
@@ -1151,6 +1210,21 @@ async def generate_generation_service(
|
||||
return response
|
||||
|
||||
|
||||
async def run_generation_job_service(
|
||||
job_id: str,
|
||||
db: AsyncSession,
|
||||
) -> GenerationJob | None:
|
||||
"""Claim and execute one generation job from the background queue."""
|
||||
|
||||
job = await claim_generation_job_for_worker(db, job_id=job_id)
|
||||
if job is None:
|
||||
logger.info("generation_job_execution_skipped", job_id=job_id)
|
||||
return None
|
||||
|
||||
await execute_generation_job_service(job, db)
|
||||
return job
|
||||
|
||||
|
||||
async def _generate_generation_service_with_job(
|
||||
request: GenerationRequest,
|
||||
user_id: str,
|
||||
|
||||
Reference in New Issue
Block a user