fix(compare-record): admin 放行 cancelled 筛选 + llm_calls 拉取改后台任务
- admin 列表 status pattern 加 cancelled(客户端会上报用户终止比价) - 上报端点拉 pricebot llm_calls 改 BackgroundTasks 异步回填, 不阻塞上报响应(独立 session) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ def list_comparison_records(
|
||||
db: AdminDb,
|
||||
user_id: Annotated[int | None, Query()] = None,
|
||||
phone: Annotated[str | None, Query(description="手机号前缀")] = None,
|
||||
status: Annotated[str | None, Query(pattern="^(success|failed)$")] = None,
|
||||
status: Annotated[str | None, Query(pattern="^(success|failed|cancelled)$")] = None,
|
||||
business_type: Annotated[str | None, Query()] = None,
|
||||
limit: Annotated[int, Query(ge=1, le=100)] = 20,
|
||||
cursor: Annotated[int | None, Query()] = None,
|
||||
|
||||
@@ -15,9 +15,11 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query, status
|
||||
from fastapi import APIRouter, BackgroundTasks, HTTPException, Query, status
|
||||
|
||||
from app.api.deps import CurrentUser, DbSession
|
||||
from app.db.session import SessionLocal
|
||||
from app.models.comparison import ComparisonRecord
|
||||
from app.repositories import comparison as crud_compare
|
||||
from app.services.pricebot_llm_calls import fetch_llm_calls
|
||||
from app.schemas.compare_record import (
|
||||
@@ -40,29 +42,49 @@ router = APIRouter(prefix="/api/v1/compare", tags=["compare-record"])
|
||||
summary="上报一次比价结果(幂等)",
|
||||
)
|
||||
def report_record(
|
||||
payload: ComparisonRecordIn, user: CurrentUser, db: DbSession
|
||||
payload: ComparisonRecordIn,
|
||||
user: CurrentUser,
|
||||
db: DbSession,
|
||||
background_tasks: BackgroundTasks,
|
||||
) -> ComparisonRecordCreatedOut:
|
||||
rec = crud_compare.upsert_record(db, user_id=user.id, payload=payload)
|
||||
# 同机拉 pricebot 本次比价的 LLM 调用明细落库(best-effort,失败不阻断上报)。
|
||||
# llm_call_count/retry_count 直接由明细派生:次数=条数,重试=带 error 的条数。
|
||||
calls = fetch_llm_calls(rec.trace_id)
|
||||
if calls:
|
||||
rec.llm_calls = calls
|
||||
rec.llm_call_count = len(calls)
|
||||
rec.retry_count = sum(1 for c in calls if c.get("error"))
|
||||
db.commit()
|
||||
# LLM 调用明细异步回填:同机拉 pricebot llm_calls 最长 5s 且是 best-effort,放后台
|
||||
# 任务做,不阻塞上报响应(顺带给 pricebot 落盘留足余量)。upsert 已 commit,后台用
|
||||
# 独立 session 按 record id 回填 llm_calls + 派生 llm_call_count/retry_count。
|
||||
background_tasks.add_task(_backfill_llm_calls, rec.id, rec.trace_id)
|
||||
logger.info(
|
||||
"compare record user=%s trace=%s biz=%s status=%s saved=%s llm_calls=%d",
|
||||
"compare record user=%s trace=%s biz=%s status=%s saved=%s (llm_calls backfill queued)",
|
||||
user.id,
|
||||
rec.trace_id,
|
||||
rec.business_type,
|
||||
rec.status,
|
||||
rec.saved_amount_cents,
|
||||
len(calls),
|
||||
)
|
||||
return ComparisonRecordCreatedOut(id=rec.id)
|
||||
|
||||
|
||||
def _backfill_llm_calls(record_id: int, trace_id: str) -> None:
|
||||
"""后台回填本次比价的 LLM 调用明细 + 派生 llm_call_count/retry_count。
|
||||
独立 DB session(请求 session 此时已关);拉取/写库失败只 log,绝不影响已落库的上报。"""
|
||||
calls = fetch_llm_calls(trace_id)
|
||||
if not calls:
|
||||
return
|
||||
db = SessionLocal()
|
||||
try:
|
||||
rec = db.get(ComparisonRecord, record_id)
|
||||
if rec is None:
|
||||
return
|
||||
rec.llm_calls = calls
|
||||
rec.llm_call_count = len(calls)
|
||||
rec.retry_count = sum(1 for c in calls if c.get("error"))
|
||||
db.commit()
|
||||
logger.info("backfill llm_calls trace=%s n=%d", trace_id, len(calls))
|
||||
except Exception as e: # noqa: BLE001 best-effort
|
||||
logger.warning("backfill llm_calls failed trace=%s: %s", trace_id, e)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/stats",
|
||||
response_model=CompareStatsOut,
|
||||
|
||||
Reference in New Issue
Block a user