diff --git a/backend/crates/gateway-store/tests/postgres/mod.rs b/backend/crates/gateway-store/tests/postgres/mod.rs index bf678ed2c..454e08095 100644 --- a/backend/crates/gateway-store/tests/postgres/mod.rs +++ b/backend/crates/gateway-store/tests/postgres/mod.rs @@ -156,7 +156,7 @@ async fn connect_and_migrate_should_apply_all_migrations_once_and_reopen_cleanly .expect("drop migration test database"); admin.close().await; - assert_eq!((first_table_count, migration_count), (10, 4)); + assert_eq!((first_table_count, migration_count), (10, 1)); assert_eq!(response_id_types, ["bytea", "bytea"]); assert!(!raw_response_id_index_exists); } diff --git a/backend/migrations/.frozen-sha256 b/backend/migrations/.frozen-sha256 index 46acdc090..c0e2f59c6 100644 --- a/backend/migrations/.frozen-sha256 +++ b/backend/migrations/.frozen-sha256 @@ -1,4 +1 @@ -54be07512951a561391b6e611355a1bfc119d82363253fb9bbdb225c9e3e39bb 0001_initial.sql -f480ac4cb70f6963eee71c0b8a67777ebb492f85501c90ebe7544bee0b2c0525 0002_remove_account_cooldown.sql -5cf5b5387c66b4d437d79c002cec46cb85196789060fa87c39e97a382487cac9 0004_fix_quota_limit_reached_null.sql -a3f236d558e7598f69277520458c801ee43130f7704ca25455df468cf8899ff2 0003_materialize_quota_limit_reached.sql +609d455f410f7be362bcdce841630728aaf2681f5cd6b2a6012529e5f8b8b1f6 0001_initial.sql diff --git a/backend/migrations/0001_initial.sql b/backend/migrations/0001_initial.sql index 012ec3d70..827575831 100644 --- a/backend/migrations/0001_initial.sql +++ b/backend/migrations/0001_initial.sql @@ -131,9 +131,8 @@ create table provider_accounts ( next_refresh_at timestamptz, enabled boolean not null default true, availability text not null default 'unknown', - availability_reason text, - cooldown_until timestamptz, provider_quota_json jsonb, + quota_limit_reached boolean not null default false, availability_observed_at timestamptz not null, quota_observed_at timestamptz, created_at timestamptz not null, @@ -163,23 +162,12 @@ create table provider_accounts ( availability in ( 'unknown', 'ready', - 'cooldown', 'quota_exhausted', 'expired', 'banned', 'invalid' ) ), - constraint provider_accounts_cooldown_ck check ( - ( - availability != 'cooldown' - or cooldown_until is not null - ) - and ( - cooldown_until is null - or availability in ('cooldown', 'quota_exhausted') - ) - ), constraint provider_accounts_time_ck check ( created_at <= updated_at and availability_observed_at <= updated_at @@ -196,7 +184,7 @@ create unique index provider_accounts_upstream_identity_uq create index provider_accounts_runtime_idx on provider_accounts (provider_kind, enabled, id); create index provider_accounts_availability_idx - on provider_accounts (availability, cooldown_until, id); + on provider_accounts (availability, id); create index provider_accounts_access_expiry_idx on provider_accounts (access_token_expires_at, id); create index provider_accounts_refresh_due_idx @@ -235,8 +223,6 @@ create table model_requests ( outcome text not null default 'running', client_status_code integer, upstream_status_code integer, - -- Provider response IDs are opaque JSON strings. Bytes preserve embedded NUL - -- and avoid imposing PostgreSQL text-index limits on protocol handles. client_response_id bytea, upstream_request_id text, upstream_response_id bytea, @@ -438,6 +424,7 @@ create index model_requests_running_deadline_idx create index model_requests_retention_idx on model_requests (completed_at) where outcome <> 'running'; + -- 运行期警告与错误事件。 create table ops_events ( id text primary key, @@ -691,11 +678,9 @@ create unique index backup_records_active_uq create unique index backup_records_object_key_uq on backup_records (object_key) where object_key is not null; --- 同时服务 retentionDays 与 retentionCount。 create index backup_records_scheduled_completed_idx on backup_records (completed_at desc, id desc) where trigger_kind = 'scheduled' and status = 'completed'; --- 可清理记录(expires_at 已到期且非活跃)的扫描索引。 create index backup_records_retention_idx on backup_records (expires_at) where expires_at is not null and status in ('completed', 'failed'); diff --git a/backend/migrations/0002_remove_account_cooldown.sql b/backend/migrations/0002_remove_account_cooldown.sql deleted file mode 100644 index 29f0b1ac8..000000000 --- a/backend/migrations/0002_remove_account_cooldown.sql +++ /dev/null @@ -1,43 +0,0 @@ --- 移除账号级 cooldown 状态模型(照 v2 语义:429 限流不进 availability,由 quota 数据驱动)。 --- --- 存量迁移: --- - availability='cooldown' 的账号:429/Cloudflare 等临时冷却 → 'ready' --- (限流事实留在 provider_quota_json,由投影滚动兜底); --- 402 语义的 usage_limit_exhausted 且未到期 → 'quota_exhausted'。 - --- 1. 迁移存量 cooldown 账号。 -update provider_accounts -set availability = case - when availability_reason = 'usage_limit_exhausted' - and cooldown_until is not null - and cooldown_until > now() - then 'quota_exhausted' - else 'ready' - end -where availability = 'cooldown'; - --- 2. 删除依赖 cooldown_until 的约束与索引。 -alter table provider_accounts drop constraint provider_accounts_cooldown_ck; -drop index provider_accounts_availability_idx; - --- 3. availability CHECK 去掉 'cooldown'。 -alter table provider_accounts drop constraint provider_accounts_availability_ck; -alter table provider_accounts - add constraint provider_accounts_availability_ck check ( - availability in ( - 'unknown', - 'ready', - 'quota_exhausted', - 'expired', - 'banned', - 'invalid' - ) - ); - --- 4. 删除列。 -alter table provider_accounts drop column availability_reason; -alter table provider_accounts drop column cooldown_until; - --- 5. 重建可用性索引(不含 cooldown_until)。 -create index provider_accounts_availability_idx - on provider_accounts (availability, id); diff --git a/backend/migrations/0003_materialize_quota_limit_reached.sql b/backend/migrations/0003_materialize_quota_limit_reached.sql deleted file mode 100644 index e64b21f7e..000000000 --- a/backend/migrations/0003_materialize_quota_limit_reached.sql +++ /dev/null @@ -1,20 +0,0 @@ --- 物化快照级限流事实:Dashboard 复用 Provider 解析结果,不再 SQL 解析 raw quota JSON。 --- --- `quota_limit_reached` 由 Provider 在写 quota 时计算(快照级:顶层或任一窗口触顶, --- 已过 reset 的窗口不计数),Admin/Dashboard 直接读该列。 - -alter table provider_accounts - add column quota_limit_reached boolean not null default false; - --- 存量回填:从现有 raw JSON 推导(仅 primary_window 的 limit_reached + reset 未过期)。 -update provider_accounts -set quota_limit_reached = coalesce( - provider_quota_json is not null - and provider_quota_json->'rate_limit'->>'limit_reached' = 'true' - and ( - provider_quota_json->'rate_limit'->'primary_window'->>'reset_at' is null - or (provider_quota_json->'rate_limit'->'primary_window'->>'reset_at')::bigint > extract(epoch from now())::bigint - ), - false -) -where provider_quota_json is not null; diff --git a/backend/migrations/0004_fix_quota_limit_reached_null.sql b/backend/migrations/0004_fix_quota_limit_reached_null.sql deleted file mode 100644 index 63385a671..000000000 --- a/backend/migrations/0004_fix_quota_limit_reached_null.sql +++ /dev/null @@ -1,8 +0,0 @@ --- 修正 0003 存量回填:raw JSON 缺 rate_limit 键时表达式为 NULL, --- 赋 NULL 违反 not-null 约束。0004 把仍为 NULL 的行兜底为 false --- (0003 已应用的环境,add column 用 default false 填充,通常无 NULL; --- 本迁移保证任何环境下该列都非 NULL)。 - -update provider_accounts -set quota_limit_reached = coalesce(quota_limit_reached, false) -where quota_limit_reached is null;