Files
Aether/_deprecated_py_src/services/task/execute/failure.py

108 lines
4.0 KiB
Python
Raw Normal View History

from __future__ import annotations
from typing import Any
import httpx
from src.core.exceptions import ProviderNotAvailableException
from src.core.logger import logger
from src.services.request.result import RequestMetadata
class TaskFailureOperationsService:
"""任务失败收敛相关操作(异常元数据与统一抛错)。"""
@staticmethod
def attach_metadata_to_error(
error: Exception | None,
candidate: Any | None,
model_name: str,
api_format: str,
) -> None:
"""Attach candidate metadata onto exception for usage recording."""
if not error or not candidate:
return
existing_metadata = getattr(error, "request_metadata", None)
if existing_metadata and getattr(existing_metadata, "api_format", None):
return
metadata = RequestMetadata(
provider_request_headers=(
getattr(existing_metadata, "provider_request_headers", {})
if existing_metadata
else {}
),
provider=getattr(existing_metadata, "provider", None) or str(candidate.provider.name),
model=getattr(existing_metadata, "model", None) or model_name,
provider_id=getattr(existing_metadata, "provider_id", None)
or str(candidate.provider.id),
provider_endpoint_id=(
getattr(existing_metadata, "provider_endpoint_id", None)
or str(candidate.endpoint.id)
),
provider_api_key_id=(
getattr(existing_metadata, "provider_api_key_id", None) or str(candidate.key.id)
),
api_format=api_format,
)
setattr(error, "request_metadata", metadata)
@staticmethod
def raise_all_failed_exception(
request_id: str | None,
max_attempts: int,
last_candidate: Any | None,
model_name: str,
api_format: str,
last_error: Exception | None = None,
) -> None:
"""Raise a unified 'all candidates failed' exception."""
logger.error(" [{}] 所有 {} 个组合均失败", request_id, max_attempts)
request_metadata = None
if last_candidate:
request_metadata = {
"provider": last_candidate.provider.name,
"model": model_name,
"provider_id": str(last_candidate.provider.id),
"provider_endpoint_id": str(last_candidate.endpoint.id),
"provider_api_key_id": str(last_candidate.key.id),
"api_format": api_format,
}
upstream_status: int | None = None
upstream_response: str | None = None
if last_error:
if isinstance(last_error, httpx.HTTPStatusError):
upstream_status = last_error.response.status_code
upstream_response = getattr(last_error, "upstream_response", None)
if not upstream_response:
try:
upstream_response = last_error.response.text
except Exception:
pass
else:
upstream_status = getattr(last_error, "upstream_status", None)
upstream_response = getattr(last_error, "upstream_response", None)
if (
not upstream_response
or not upstream_response.strip()
or upstream_response.startswith("Unable to read")
):
upstream_response = str(last_error)
friendly_message = "服务暂时不可用,请稍后重试"
if last_error:
last_error_message = getattr(last_error, "message", None)
if last_error_message and isinstance(last_error_message, str):
friendly_message = last_error_message
raise ProviderNotAvailableException(
friendly_message,
request_metadata=request_metadata,
upstream_status=upstream_status,
upstream_response=upstream_response,
)