feat(insta-lab): internal webhook /api/internal/insta/update (SP-4)

Windows insta-render worker가 작업 진행률·완료·실패를 보고할 수신부.
X-Internal-Key 인증 필수. 4건의 단위 테스트로 status·error·result_path 검증.

Plan-B-Insta Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 01:57:17 +09:00
parent 5ed9d265f6
commit 0c12c3527f
2 changed files with 143 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
"""SP-4 — Windows insta-render → NAS internal webhook.
POST /api/internal/insta/update
- X-Internal-Key 인증 필수
- task DB row update (status, progress, result_path, error)
- result_path는 nginx 서빙 경로 (예: /media/insta/{slate_id}/01.png)
- succeeded 시 params에서 slate_id 추출 → result_id 세팅
"""
from __future__ import annotations
import json
import logging
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
from . import db
from .auth import verify_internal_key
logger = logging.getLogger(__name__)
router = APIRouter()
class UpdatePayload(BaseModel):
task_id: str
status: str = Field(..., description="processing|succeeded|failed")
progress: int = Field(..., ge=0, le=100)
result_path: Optional[str] = None
error: Optional[str] = None
@router.post(
"/api/internal/insta/update",
dependencies=[Depends(verify_internal_key)],
)
def insta_update(payload: UpdatePayload):
task = db.get_task(payload.task_id)
if task is None:
raise HTTPException(404, f"task not found: {payload.task_id}")
result_id = None
if payload.status == "succeeded":
try:
# DB stores params (not input_data) from create_task
params_data = json.loads(task.get("params") or "{}")
result_id = params_data.get("slate_id")
except (ValueError, TypeError):
pass
db.update_task(
payload.task_id,
payload.status,
payload.progress,
message=payload.result_path or "",
result_id=result_id,
error=payload.error,
)
logger.info(
"internal/insta/update task=%s status=%s progress=%d",
payload.task_id, payload.status, payload.progress,
)
return {"ok": True}