From be2a136392020f3677e424fe5b530e2ad6d0d525 Mon Sep 17 00:00:00 2001 From: iven Date: Wed, 15 Apr 2026 01:41:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(saas):=20relay=5Ftasks=20=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=B8=85=E7=90=86=20=E2=80=94=20=E6=AF=8F5?= =?UTF-8?q?=E5=88=86=E9=92=9F=E6=89=AB=E6=8F=8F=20processing=20>10min=20?= =?UTF-8?q?=E6=A0=87=E8=AE=B0=20failed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - scheduler.rs: 新增 start_db_cleanup_tasks 中的 relay 超时清理定时任务 - status=processing 且 updated_at 超过 10 分钟的 relay_task 自动标记为 failed - 避免 Provider key 禁用后 relay_task 永久停留在 processing 状态 --- crates/zclaw-saas/src/scheduler.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/zclaw-saas/src/scheduler.rs b/crates/zclaw-saas/src/scheduler.rs index 17184eb..cbb4201 100644 --- a/crates/zclaw-saas/src/scheduler.rs +++ b/crates/zclaw-saas/src/scheduler.rs @@ -82,6 +82,7 @@ pub fn start_scheduler(config: &SchedulerConfig, _db: PgPool, dispatcher: Worker pub fn start_db_cleanup_tasks(db: PgPool) { let db_devices = db.clone(); let db_key_pool = db.clone(); + let db_relay = db.clone(); // 每 24 小时清理不活跃设备 tokio::spawn(async move { @@ -128,6 +129,28 @@ pub fn start_db_cleanup_tasks(db: PgPool) { } } }); + + // 每 5 分钟清理超时的 relay_tasks(status=processing 且 updated_at 超过 10 分钟) + tokio::spawn(async move { + let mut interval = tokio::time::interval(Duration::from_secs(300)); + loop { + interval.tick().await; + match sqlx::query( + "UPDATE relay_tasks SET status = 'failed', error_message = 'timeout: upstream not responding', completed_at = NOW() \ + WHERE status = 'processing' AND updated_at < NOW() - INTERVAL '10 minutes'" + ) + .execute(&db_relay) + .await + { + Ok(result) => { + if result.rows_affected() > 0 { + tracing::warn!("Cleaned up {} timed-out relay tasks (>10m processing)", result.rows_affected()); + } + } + Err(e) => tracing::error!("Relay task timeout cleanup failed: {}", e), + } + } + }); } /// 用户任务调度器