mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/ - 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层 - 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构 - 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations) - 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image - 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
This commit is contained in:
201
_deprecated_py_src/services/task/submit/response.py
Normal file
201
_deprecated_py_src/services/task/submit/response.py
Normal file
@@ -0,0 +1,201 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from src.core.logger import logger
|
||||
from src.services.billing.rule_service import BillingRuleLookupResult
|
||||
from src.services.candidate.submit import SubmitOutcome, UpstreamClientRequestError
|
||||
from src.services.task.submit.outcome_builder import (
|
||||
AsyncSubmitOutcomeBuilderService,
|
||||
)
|
||||
from src.services.task.submit.record import AsyncSubmitRecordService
|
||||
from src.services.task.submit.rule_decider import AsyncSubmitRuleDeciderService
|
||||
|
||||
|
||||
class AsyncSubmitResponseService:
|
||||
"""异步提交响应判定服务。"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
db: Session,
|
||||
*,
|
||||
record_ops: AsyncSubmitRecordService,
|
||||
sanitize: Callable[[str], str],
|
||||
extract_response_text: Callable[[httpx.Response], str],
|
||||
match_provider_failover_rule: Callable[..., str | None],
|
||||
) -> None:
|
||||
self.db = db
|
||||
self._record_ops = record_ops
|
||||
self._sanitize = sanitize
|
||||
self._extract_response_text = extract_response_text
|
||||
self._rule_decider = AsyncSubmitRuleDeciderService(
|
||||
match_provider_failover_rule=match_provider_failover_rule
|
||||
)
|
||||
self._outcome_builder = AsyncSubmitOutcomeBuilderService(sanitize=sanitize)
|
||||
|
||||
def handle_submit_exception(
|
||||
self,
|
||||
*,
|
||||
record_id: str | None,
|
||||
candidate_info: dict[str, Any],
|
||||
exc: Exception,
|
||||
) -> tuple[None, None]:
|
||||
error_type = type(exc).__name__
|
||||
error_msg = self._sanitize(str(exc))
|
||||
candidate_info.update(
|
||||
{
|
||||
"attempt_status": "exception",
|
||||
"error_type": error_type,
|
||||
"error_message": error_msg,
|
||||
}
|
||||
)
|
||||
self._record_ops.mark_failed(
|
||||
record_id=record_id,
|
||||
error_type=error_type,
|
||||
error_message=error_msg,
|
||||
)
|
||||
return None, None
|
||||
|
||||
def handle_submit_response(
|
||||
self,
|
||||
*,
|
||||
candidate: Any,
|
||||
record_id: str | None,
|
||||
candidate_info: dict[str, Any],
|
||||
candidate_keys: list[dict[str, Any]],
|
||||
rule_lookup: BillingRuleLookupResult | None,
|
||||
response: httpx.Response,
|
||||
extract_external_task_id: Any,
|
||||
) -> tuple[SubmitOutcome | None, int | None]:
|
||||
last_status_code = int(getattr(response, "status_code", 0) or 0)
|
||||
|
||||
if response.status_code >= 400:
|
||||
error_text = self._extract_response_text(response)
|
||||
error_msg = self._sanitize(error_text)
|
||||
candidate_info.update(
|
||||
{
|
||||
"attempt_status": "http_error",
|
||||
"status_code": response.status_code,
|
||||
"error_message": error_msg,
|
||||
}
|
||||
)
|
||||
self._record_ops.mark_failed(
|
||||
record_id=record_id,
|
||||
status_code=response.status_code,
|
||||
error_type="http_error",
|
||||
error_message=error_msg,
|
||||
)
|
||||
|
||||
stop_pattern = self._rule_decider.detect_error_stop_pattern(
|
||||
candidate=candidate,
|
||||
response_text=error_text,
|
||||
status_code=response.status_code,
|
||||
)
|
||||
if stop_pattern:
|
||||
logger.info(
|
||||
"[TaskService] 错误终止规则命中: pattern={}, status_code={}, provider={}",
|
||||
stop_pattern,
|
||||
response.status_code,
|
||||
candidate.provider.name,
|
||||
)
|
||||
candidate_info["stop_rule_pattern"] = stop_pattern
|
||||
try:
|
||||
self.db.commit()
|
||||
except Exception:
|
||||
self.db.rollback()
|
||||
raise UpstreamClientRequestError(
|
||||
response=response,
|
||||
candidate_keys=candidate_keys,
|
||||
)
|
||||
return None, last_status_code
|
||||
|
||||
success_text = self._extract_response_text(response)
|
||||
success_continue_pattern = self._rule_decider.detect_success_failover_pattern(
|
||||
candidate=candidate,
|
||||
response_text=success_text,
|
||||
status_code=response.status_code,
|
||||
)
|
||||
if success_continue_pattern:
|
||||
logger.info(
|
||||
"[TaskService] 成功转移规则命中: pattern={}, status_code={}, provider={}",
|
||||
success_continue_pattern,
|
||||
response.status_code,
|
||||
candidate.provider.name,
|
||||
)
|
||||
failover_reason = f"success_failover_rule_matched:{success_continue_pattern}"
|
||||
candidate_info.update(
|
||||
{
|
||||
"attempt_status": "success_failover",
|
||||
"status_code": response.status_code,
|
||||
"error_message": failover_reason,
|
||||
"success_rule_pattern": success_continue_pattern,
|
||||
}
|
||||
)
|
||||
self._record_ops.mark_failed(
|
||||
record_id=record_id,
|
||||
status_code=response.status_code,
|
||||
error_type="success_failover_pattern",
|
||||
error_message=failover_reason,
|
||||
)
|
||||
return None, last_status_code
|
||||
|
||||
parse_result = self._outcome_builder.parse_payload(response=response)
|
||||
if parse_result.error_type:
|
||||
candidate_info.update(
|
||||
{
|
||||
"attempt_status": "invalid_json",
|
||||
"error_type": parse_result.error_type,
|
||||
"error_message": parse_result.error_message,
|
||||
}
|
||||
)
|
||||
self._record_ops.mark_failed(
|
||||
record_id=record_id,
|
||||
status_code=response.status_code,
|
||||
error_type="invalid_json",
|
||||
error_message=parse_result.error_message or "invalid_json",
|
||||
)
|
||||
return None, last_status_code
|
||||
|
||||
payload = parse_result.payload
|
||||
external_task_id = extract_external_task_id(payload or {})
|
||||
if not external_task_id:
|
||||
candidate_info.update(
|
||||
{
|
||||
"attempt_status": "empty_task_id",
|
||||
"error_message": "Upstream returned empty task id",
|
||||
}
|
||||
)
|
||||
self._record_ops.mark_failed(
|
||||
record_id=record_id,
|
||||
status_code=response.status_code,
|
||||
error_type="empty_task_id",
|
||||
error_message="Upstream returned empty task id",
|
||||
)
|
||||
return None, last_status_code
|
||||
|
||||
# Success
|
||||
candidate_info.update({"attempt_status": "success", "selected": True})
|
||||
self._record_ops.mark_success(
|
||||
record_id=record_id,
|
||||
status_code=response.status_code,
|
||||
)
|
||||
try:
|
||||
self.db.commit()
|
||||
except Exception:
|
||||
self.db.rollback()
|
||||
|
||||
return (
|
||||
self._outcome_builder.build_success_outcome(
|
||||
candidate=candidate,
|
||||
candidate_keys=candidate_keys,
|
||||
external_task_id=str(external_task_id),
|
||||
rule_lookup=rule_lookup,
|
||||
payload=payload,
|
||||
response=response,
|
||||
),
|
||||
last_status_code,
|
||||
)
|
||||
Reference in New Issue
Block a user