Files

53 lines
1.7 KiB
Python

"""投顾 Agent 的统一超时与降级执行器。"""
from __future__ import annotations
import asyncio
import inspect
import logging
from dataclasses import dataclass
from typing import Awaitable, Callable, TypeVar
from utils.exceptions import ApiError
T = TypeVar("T")
logger = logging.getLogger("advisor_agent.fallback")
@dataclass(frozen=True)
class FallbackResult:
value: object
degraded: bool
code: int | None = None
async def call_with_fallback(
primary: Callable[[], Awaitable[T]],
secondary: Callable[[], Awaitable[T]] | None,
*,
timeout: float,
degraded_code: int,
on_degraded: Callable[[Exception], None] | None = None,
) -> FallbackResult:
try:
return FallbackResult(
value=await asyncio.wait_for(primary(), timeout=timeout),
degraded=False,
)
except Exception as primary_error:
logger.warning("advisor dependency degraded; using fallback", exc_info=primary_error)
if on_degraded is not None:
try:
callback_result = on_degraded(primary_error)
if inspect.isawaitable(callback_result):
await callback_result
except Exception:
logger.warning("advisor degradation audit callback failed", exc_info=True)
if secondary is None:
raise ApiError(degraded_code, "Agent核心服务调用失败") from primary_error
try:
value = await asyncio.wait_for(secondary(), timeout=timeout)
except Exception as secondary_error:
raise ApiError(degraded_code, "Agent降级服务调用失败") from secondary_error
return FallbackResult(value=value, degraded=True, code=degraded_code)