mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
fix(adaptive): 修复 429 计数归零写入及 reset 语义
- sql.rs: UPDATE 时对 concurrent_429_count / rpm_429_count 加 COALESCE(, 0),避免 None 覆写为 NULL - effects.rs: rpm_429_count 始终写入 Some(projection.rpm_429_count),不再过滤零值;新增 unknown-429 场景下零值持久化的单元测试 - adaptive.rs: reset 接口将两个计数字段置为 Some(0) 而非 None,与数据库默认语义对齐;同步修正集成测试断言 - docker-compose.build.yml: 补充 AETHER_GATEWAY_AUTO_PREPARE_DATABASE 默认开启 - README.md: 同步说明 build compose 也已默认开启自动迁移
This commit is contained in:
@@ -113,7 +113,7 @@ client -> rust frontdoor (aether-gateway) -> execution_runtime/provider transpor
|
||||
- `./dev.sh` 默认把 `AETHER_GATEWAY_VIDEO_TASK_TRUTH_SOURCE_MODE` 设为 `rust-authoritative`,避免本地还依赖 Python sync report 语义。
|
||||
- 空库首次启动会自动初始化到当前 baseline。
|
||||
- `aether-gateway` 默认启动不会自动应用后续 schema migration;如果数据库版本落后,服务会拒绝启动,并提示先执行 `aether-gateway --migrate`。
|
||||
- 仓库自带的 `docker-compose.yml` 已把 `AETHER_GATEWAY_AUTO_PREPARE_DATABASE` 设为默认开启,因此 `docker compose up -d` 会在监听端口前自动执行挂起的 migration 和 backfill。
|
||||
- 仓库自带的 `docker-compose.yml` 和 `docker-compose.build.yml` 都已把 `AETHER_GATEWAY_AUTO_PREPARE_DATABASE` 设为默认开启,因此无论是预构建镜像部署还是 `./deploy.sh` / 本地构建 compose,常规启动都会在监听端口前自动执行挂起的 migration 和 backfill。
|
||||
|
||||
## Aether Proxy (可选)
|
||||
|
||||
@@ -134,7 +134,7 @@ Aether Proxy 是配套的正向代理节点,部署在海外 VPS 上,为墙
|
||||
|
||||
- `APP_PORT`:`aether-gateway` 唯一监听端口,固定绑定 `0.0.0.0:${APP_PORT}`
|
||||
- `DATABASE_URL` / `REDIS_URL`:`aether-gateway` 直接读取的共享后端连接串
|
||||
- `AETHER_GATEWAY_AUTO_PREPARE_DATABASE`:常规启动前自动执行挂起的 schema migration 和 backfill;仓库自带的 `docker-compose.yml` 默认开启
|
||||
- `AETHER_GATEWAY_AUTO_PREPARE_DATABASE`:常规启动前自动执行挂起的 schema migration 和 backfill;仓库自带的 `docker-compose.yml` 和 `docker-compose.build.yml` 默认开启
|
||||
- `JWT_SECRET_KEY` / `ENCRYPTION_KEY`:认证和敏感数据加密所需密钥
|
||||
- `API_KEY_PREFIX`:用户和管理员新建 API Key 时使用的前缀,默认 `sk`
|
||||
- `PAYMENT_CALLBACK_SECRET`:支付回调公开入口的共享密钥;未配置时相关路由保持禁用
|
||||
@@ -179,7 +179,7 @@ systemd 的 `.env` 必须保持简单 `KEY=VALUE` 形式,不要写 `export`、
|
||||
|
||||
**没有备份的情况:**
|
||||
|
||||
当前不应该再依赖旧的 `alembic downgrade` 路线。空库首次启动会自动初始化;如果开启 `AETHER_GATEWAY_AUTO_PREPARE_DATABASE=true`(仓库自带 `docker-compose.yml` 默认如此),常规服务启动也会自动应用挂起的 migration/backfill。无论是否自动执行,只要本次发布带来了不可逆的数据结构变化,没有备份就不能保证安全回滚。因此升级前强烈建议先备份 `Postgres`。
|
||||
当前不应该再依赖旧的 `alembic downgrade` 路线。空库首次启动会自动初始化;如果开启 `AETHER_GATEWAY_AUTO_PREPARE_DATABASE=true`(仓库自带的两份 compose 默认都如此),常规服务启动也会自动应用挂起的 migration/backfill。无论是否自动执行,只要本次发布带来了不可逆的数据结构变化,没有备份就不能保证安全回滚。因此升级前强烈建议先备份 `Postgres`。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -134,8 +134,8 @@ impl<'a> AdminAppState<'a> {
|
||||
return Ok(admin_adaptive_key_not_found_response(key_id));
|
||||
};
|
||||
key.learned_rpm_limit = None;
|
||||
key.concurrent_429_count = None;
|
||||
key.rpm_429_count = None;
|
||||
key.concurrent_429_count = Some(0);
|
||||
key.rpm_429_count = Some(0);
|
||||
key.last_429_at_unix_secs = None;
|
||||
key.last_429_type = None;
|
||||
key.adjustment_history = None;
|
||||
|
||||
@@ -300,7 +300,7 @@ async fn record_adaptive_rate_limit_effect(
|
||||
};
|
||||
|
||||
let mut updated_key = current_key.clone();
|
||||
updated_key.rpm_429_count = Some(projection.rpm_429_count).filter(|value| *value > 0);
|
||||
updated_key.rpm_429_count = Some(projection.rpm_429_count);
|
||||
updated_key.learned_rpm_limit = projection.learned_rpm_limit;
|
||||
updated_key.last_429_at_unix_secs = Some(projection.last_429_at_unix_secs);
|
||||
updated_key.last_429_type = Some(projection.last_429_type);
|
||||
@@ -1315,6 +1315,40 @@ mod tests {
|
||||
assert_eq!(stored_key.last_429_type, None);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn adaptive_rate_limit_effect_persists_zero_rpm_count_for_unknown_429() {
|
||||
let mut key = sample_health_key();
|
||||
key.rpm_limit = None;
|
||||
key.learned_rpm_limit = Some(20);
|
||||
let state = adaptive_state_with_request_candidates(key, Vec::new());
|
||||
let plan = sample_plan();
|
||||
|
||||
apply_local_execution_effect(
|
||||
&state,
|
||||
LocalExecutionEffectContext {
|
||||
plan: &plan,
|
||||
report_context: None,
|
||||
},
|
||||
LocalExecutionEffect::AdaptiveRateLimit(LocalAdaptiveRateLimitEffect {
|
||||
status_code: 429,
|
||||
classification: LocalFailoverClassification::RetryStatusCode,
|
||||
headers: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let stored_key = state
|
||||
.read_provider_catalog_keys_by_ids(std::slice::from_ref(&plan.key_id))
|
||||
.await
|
||||
.expect("provider catalog keys should load")
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("stored key should exist");
|
||||
assert_eq!(stored_key.rpm_429_count, Some(0));
|
||||
assert_eq!(stored_key.learned_rpm_limit, Some(19));
|
||||
assert_eq!(stored_key.last_429_type.as_deref(), Some("unknown"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn adaptive_success_effect_expands_limit_from_recent_rpm_usage() {
|
||||
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
|
||||
|
||||
@@ -440,8 +440,8 @@ async fn gateway_resets_admin_adaptive_learning_locally_with_trusted_admin_princ
|
||||
.await
|
||||
.expect("repository query should succeed");
|
||||
assert_eq!(updated[0].learned_rpm_limit, None);
|
||||
assert_eq!(updated[0].concurrent_429_count, None);
|
||||
assert_eq!(updated[0].rpm_429_count, None);
|
||||
assert_eq!(updated[0].concurrent_429_count, Some(0));
|
||||
assert_eq!(updated[0].rpm_429_count, Some(0));
|
||||
assert_eq!(updated[0].adjustment_history, None);
|
||||
|
||||
gateway_handle.abort();
|
||||
|
||||
@@ -1738,8 +1738,8 @@ SET
|
||||
END,
|
||||
oauth_invalid_reason = $26,
|
||||
status_snapshot = $27,
|
||||
concurrent_429_count = $28,
|
||||
rpm_429_count = $29,
|
||||
concurrent_429_count = COALESCE($28, 0),
|
||||
rpm_429_count = COALESCE($29, 0),
|
||||
last_429_at = CASE
|
||||
WHEN $30::double precision IS NULL THEN NULL
|
||||
ELSE TO_TIMESTAMP($30::double precision)
|
||||
|
||||
@@ -51,6 +51,7 @@ services:
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
TZ: Asia/Shanghai
|
||||
APP_PORT: ${APP_PORT:-8084}
|
||||
AETHER_GATEWAY_AUTO_PREPARE_DATABASE: ${AETHER_GATEWAY_AUTO_PREPARE_DATABASE:-true}
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
||||
Reference in New Issue
Block a user