mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
feat(pool,scheduling): 号池调度维度、配额冷却机制与管理后台重构
- 新增 scheduling_dimensions 模块,为每个 Key 计算多维调度状态(手动/冷却/熔断/成本/健康) - 新增 quota_cooldown 模块,统一判定 Key 的有效冷却原因 - Pool 管理后台 API 扩展 Key 详情字段(调度状态/维度/配额/OAuth 信息) - 前端 Pool 管理页面重写,支持调度状态展示、批量清理封禁 Key - Handler 基类增加请求调度元数据采集,stream telemetry 增强 - 请求时间线组件增强,支持 attempted 候选展示 - Kiro OAuth 凭证导入解析改进 - 新增 usage 表 provider_key 索引迁移 - 补充调度维度、配额冷却、候选枚举等单元测试 Closes #197 Co-authored-by: AAEE86 <33052466+AAEE86@users.noreply.github.com>
This commit is contained in:
@@ -310,3 +310,77 @@ async def test_submit_with_failover_filters_missing_billing_rule(
|
||||
assert submit.await_count == 1
|
||||
finally:
|
||||
config.billing_require_rule = old
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_submit_with_failover_applies_pool_reorder_before_submit(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
db = MagicMock()
|
||||
svc = TaskService(db)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"src.services.system.config.SystemConfigService.get_config",
|
||||
lambda *_args, **_kwargs: "provider",
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.services.scheduling.aware_scheduler.get_cache_aware_scheduler",
|
||||
AsyncMock(return_value=None),
|
||||
)
|
||||
|
||||
pool_candidate_a = _make_candidate(
|
||||
provider_id="pool-1",
|
||||
provider_name="pool-provider",
|
||||
endpoint_id="ep-1",
|
||||
key_id="k-a",
|
||||
key_name="key-a",
|
||||
)
|
||||
pool_candidate_b = _make_candidate(
|
||||
provider_id="pool-1",
|
||||
provider_name="pool-provider",
|
||||
endpoint_id="ep-1",
|
||||
key_id="k-b",
|
||||
key_name="key-b",
|
||||
)
|
||||
|
||||
fetch_candidates = AsyncMock(
|
||||
return_value=(
|
||||
[pool_candidate_a, pool_candidate_b],
|
||||
"gm1",
|
||||
)
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.services.candidate.resolver.CandidateResolver.fetch_candidates",
|
||||
fetch_candidates,
|
||||
)
|
||||
|
||||
reordered = [pool_candidate_b, pool_candidate_a]
|
||||
apply_pool_reorder = AsyncMock(return_value=(reordered, []))
|
||||
monkeypatch.setattr(svc, "_apply_pool_reorder", apply_pool_reorder)
|
||||
|
||||
submit = AsyncMock(return_value=httpx.Response(200, json={"id": "task-pooled"}))
|
||||
body = {"session_id": "sid-123"}
|
||||
outcome = await svc.submit_with_failover(
|
||||
api_format="openai:video",
|
||||
model_name="sora",
|
||||
affinity_key="a1",
|
||||
user_api_key=MagicMock(),
|
||||
request_id=None,
|
||||
task_type="video",
|
||||
submit_func=submit,
|
||||
extract_external_task_id=lambda payload: payload.get("id"),
|
||||
supported_auth_types={"api_key"},
|
||||
allow_format_conversion=False,
|
||||
max_candidates=10,
|
||||
request_body=body,
|
||||
)
|
||||
|
||||
assert outcome.external_task_id == "task-pooled"
|
||||
assert outcome.candidate.key.id == "k-b"
|
||||
assert submit.await_count == 1
|
||||
fetch_candidates.assert_awaited_once()
|
||||
assert fetch_candidates.await_args.kwargs.get("request_body") == body
|
||||
apply_pool_reorder.assert_awaited_once_with(
|
||||
[pool_candidate_a, pool_candidate_b],
|
||||
request_body=body,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user