refactor: 统一任务框架 Phase 3 - 用 TaskService/FailoverEngine 替代 FallbackOrchestrator

核心重构:
- 移除 FallbackOrchestrator,用 TaskService + FailoverEngine 替代
- TaskService 作为统一入口,支持 SYNC/ASYNC 两种任务模式
- FailoverEngine 实现候选遍历、重试、故障转移逻辑
- 新增 AttemptFunc/AttemptResult 协议,统一尝试结果表示

功能改进:
- 流式响应首字节探测(30s 超时,空流触发故障转移)
- 流式取消归因优化(区分客户端断连 vs 服务端中断)
- 新增 OpenAI Sora 视频取消路由 POST /v1/videos/{task_id}/cancel
- OpenAI 流式请求自动添加 stream_options.include_usage

代码规范:
- 修复 loguru 日志格式(%s → {})
- 新增 FORMAT_CONVERSION_ENABLED 环境变量说明

测试覆盖:
- test_failover_engine.py: FailoverEngine 单元测试
- test_task_service_async_execute.py: TaskService ASYNC 模式测试
- test_video_cancel_e2e.py: 视频取消端到端测试
This commit is contained in:
fawney19
2026-02-02 21:16:28 +08:00
parent ebe1a8d3e3
commit ed68aebfb0
53 changed files with 3966 additions and 2256 deletions

View File

@@ -2,7 +2,6 @@
Orchestration 模块
提供请求编排相关的组件:
- FallbackOrchestrator: 故障转移编排器,协调请求的完整生命周期
- CandidateResolver: 候选解析器,负责获取和排序可用的 Provider 组合
- RequestDispatcher: 请求分发器,负责执行单个候选请求
- ErrorClassifier: 错误分类器,负责错误分类和处理策略
@@ -10,11 +9,9 @@ Orchestration 模块
from .candidate_resolver import CandidateResolver
from .error_classifier import ErrorAction, ErrorClassifier
from .fallback_orchestrator import FallbackOrchestrator
from .request_dispatcher import RequestDispatcher
__all__ = [
"FallbackOrchestrator",
"CandidateResolver",
"RequestDispatcher",
"ErrorClassifier",

View File

@@ -77,7 +77,7 @@ class CandidateResolver:
global_model_id: str | None = None
logger.debug(
"[CandidateResolver] fetch_candidates starting: model=%s, api_format=%s",
"[CandidateResolver] fetch_candidates starting: model={}, api_format={}",
model_name,
api_format,
)
@@ -96,7 +96,7 @@ class CandidateResolver:
)
logger.debug(
"[CandidateResolver] list_all_candidates batch: offset=%d, returned=%d candidates",
"[CandidateResolver] list_all_candidates batch: offset={}, returned={} candidates",
provider_offset,
len(candidates),
)
@@ -111,7 +111,7 @@ class CandidateResolver:
provider_offset += provider_batch_size
logger.debug(
"[CandidateResolver] fetch_candidates completed: total=%d candidates",
"[CandidateResolver] fetch_candidates completed: total={} candidates",
len(all_candidates),
)

File diff suppressed because it is too large Load Diff