53 lines
1.7 KiB
Python
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)
|