From 8e6abc91e1014a7fb69d526d6e7390d8966e76bc Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 31 Mar 2026 10:14:49 +0800 Subject: [PATCH] feat(key-pool): add LRU sorting via last_used_at column - Add migration to add last_used_at TIMESTAMPTZ column to provider_keys - Update select_best_key() SQL to sort by last_used_at ASC NULLS FIRST - Update record_key_usage() to set last_used_at = NOW() on each use - Bump SCHEMA_VERSION to 10 --- .../migrations/20260401000001_provider_keys_last_used.sql | 3 +++ crates/zclaw-saas/src/db.rs | 2 +- crates/zclaw-saas/src/relay/key_pool.rs | 8 +++++++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 crates/zclaw-saas/migrations/20260401000001_provider_keys_last_used.sql diff --git a/crates/zclaw-saas/migrations/20260401000001_provider_keys_last_used.sql b/crates/zclaw-saas/migrations/20260401000001_provider_keys_last_used.sql new file mode 100644 index 0000000..25de19c --- /dev/null +++ b/crates/zclaw-saas/migrations/20260401000001_provider_keys_last_used.sql @@ -0,0 +1,3 @@ +-- 20260401000001_provider_keys_last_used.sql +-- Key Pool LRU: 记录每个 key 最后使用时间 +ALTER TABLE provider_keys ADD COLUMN IF NOT EXISTS last_used_at TIMESTAMPTZ; diff --git a/crates/zclaw-saas/src/db.rs b/crates/zclaw-saas/src/db.rs index 68f0442..b04ede7 100644 --- a/crates/zclaw-saas/src/db.rs +++ b/crates/zclaw-saas/src/db.rs @@ -4,7 +4,7 @@ use sqlx::postgres::PgPoolOptions; use sqlx::PgPool; use crate::error::SaasResult; -const SCHEMA_VERSION: i32 = 9; +const SCHEMA_VERSION: i32 = 10; /// 初始化数据库 pub async fn init_db(database_url: &str) -> SaasResult { diff --git a/crates/zclaw-saas/src/relay/key_pool.rs b/crates/zclaw-saas/src/relay/key_pool.rs index bfbab7d..011a60e 100644 --- a/crates/zclaw-saas/src/relay/key_pool.rs +++ b/crates/zclaw-saas/src/relay/key_pool.rs @@ -51,7 +51,7 @@ pub async fn select_best_key(db: &PgPool, provider_id: &str, enc_key: &[u8; 32]) LEFT JOIN key_usage_window uw ON pk.id = uw.key_id AND uw.window_minute = $1 WHERE pk.provider_id = $2 AND pk.is_active = TRUE AND (pk.cooldown_until IS NULL OR pk.cooldown_until <= $3) - ORDER BY pk.priority ASC" + ORDER BY pk.priority ASC, pk.last_used_at ASC NULLS FIRST" ).bind(¤t_minute).bind(provider_id).bind(&now).fetch_all(db).await?; for (id, key_value, priority, max_rpm, max_tpm, quota_reset_interval, req_count, token_count) in &rows { @@ -165,6 +165,12 @@ pub async fn record_key_usage( .bind(tokens).bind(&chrono::Utc::now().to_rfc3339()).bind(key_id) .execute(db).await?; + // 更新最后使用时间 (LRU 排序依据) + sqlx::query("UPDATE provider_keys SET last_used_at = NOW() WHERE id = $1") + .bind(key_id) + .execute(db) + .await?; + Ok(()) }