Files
Neo-ZQYY/apps/backend/app/routers/internal_events.py
2026-04-10 06:24:13 +08:00

139 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI_CHANGELOG
# - 2026-03-29 | Prompt: DWS_TASK_ENGINE ETL 任务 | 新建文件。
# 提供 POST /api/internal/run-job 端点,供 ETL 按 job_name 执行
# biz.trigger_jobs 中的任务。Internal-Token 认证。
# -*- coding: utf-8 -*-
"""
内部任务执行 API — ETL/内部服务调用入口。
端点:
- POST /api/internal/run-job — 按 job_name 执行 biz.trigger_jobs 中的任务
认证方式Authorization: Internal-Token {token}
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from app.auth.internal_token import verify_internal_token
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/internal", tags=["internal-events"])
class RunJobByNameRequest(BaseModel):
"""按 job_name 执行任务的请求体。"""
job_name: str = Field(..., description="任务名称,如 recall_completion_check")
class RunJobByNameResponse(BaseModel):
"""执行结果。"""
success: bool
message: str
job_name: str
class EtlCompletedRequest(BaseModel):
"""ETL 完成通知请求体。"""
pipeline: str = Field(default="api_full", description="完成的 pipeline 名称")
site_id: int | None = Field(default=None, description="门店 ID可选")
class EtlCompletedResponse(BaseModel):
"""ETL 完成编排结果。"""
success: bool
recall_result: dict | None = None
task_gen_result: dict | None = None
message: str = ""
@router.post("/etl-completed", response_model=EtlCompletedResponse)
async def etl_completed_endpoint(
body: EtlCompletedRequest,
_token: str = Depends(verify_internal_token),
) -> EtlCompletedResponse:
"""ETL pipeline 完成后的统一编排入口。
CHANGE 2026-04-07 | Fix-12ETL 完成后自动触发。
编排顺序recall_detector.run() → task_generator.run()
"""
from app.services import recall_detector, task_generator
recall_result = None
task_gen_result = None
errors = []
# Step 1: 先检查召回完成(含回溯)
try:
recall_result = recall_detector.run()
logger.info("ETL 编排 Step1 recall_detector 完成: %s", recall_result)
except Exception:
logger.exception("ETL 编排 Step1 recall_detector 失败")
errors.append("recall_detector failed")
# Step 2: 再生成新任务
try:
task_gen_result = task_generator.run()
logger.info("ETL 编排 Step2 task_generator 完成: %s", task_gen_result)
except Exception:
logger.exception("ETL 编排 Step2 task_generator 失败")
errors.append("task_generator failed")
success = len(errors) == 0
return EtlCompletedResponse(
success=success,
recall_result=recall_result,
task_gen_result=task_gen_result,
message="; ".join(errors) if errors else "ok",
)
@router.post("/run-job", response_model=RunJobByNameResponse)
async def run_job_by_name_endpoint(
body: RunJobByNameRequest,
_token: str = Depends(verify_internal_token),
) -> RunJobByNameResponse:
"""按 job_name 查找并执行 biz.trigger_jobs 中的任务。
ETL DWS_TASK_ENGINE 任务通过此端点按顺序执行后端任务引擎的各个步骤。
"""
from app.database import get_connection
from app.services.trigger_scheduler import run_job_by_id
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute(
"SELECT id FROM biz.trigger_jobs WHERE job_name = %s",
(body.job_name,),
)
row = cur.fetchone()
conn.commit()
finally:
conn.close()
if not row:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"任务 '{body.job_name}' 不存在",
)
job_id = row[0]
result = run_job_by_id(job_id)
logger.info(
"内部任务执行: job_name=%s, success=%s",
body.job_name, result.get("success"),
)
return RunJobByNameResponse(
success=result.get("success", False),
message=result.get("message", ""),
job_name=body.job_name,
)