diff --git a/apps/notes/src/main.rs b/apps/notes/src/main.rs index 153ac8c..3eabfba 100644 --- a/apps/notes/src/main.rs +++ b/apps/notes/src/main.rs @@ -114,6 +114,43 @@ async fn main() -> std::io::Result<()> { .route("/health", get(|| async { "ok" })) .merge(protected_api); + // 启动时把上次 pod 死前卡在中间状态的 recording 重新喂给 worker。 + // 状态 transcribing/summarizing 是 worker 进程内存的,pod 重启就丢, + // db 还停留在原状态 → 不 resume 永远不会再动。 + { + let stuck: Vec = { + let conn = state.db.lock().unwrap(); + let mut stmt = conn + .prepare( + "SELECT id FROM recordings + WHERE status IN ('pending', 'transcribing', 'summarizing') + ORDER BY id ASC", + ) + .expect("prepare resume query"); + stmt.query_map([], |r| r.get::<_, i64>(0)) + .expect("run resume query") + .collect::, _>>() + .expect("collect resume ids") + }; + if !stuck.is_empty() { + tracing::info!(count = stuck.len(), ids = ?stuck, "resuming stuck recordings"); + for id in stuck { + let s = state.clone(); + tokio::spawn(async move { + // 改回 pending 让 worker 从头跑(idempotent) + { + let conn = s.db.lock().unwrap(); + let _ = conn.execute( + "UPDATE recordings SET status = 'pending', error = NULL WHERE id = ?1", + params![id], + ); + } + process_recording(s, id).await; + }); + } + } + } + let app = cube_core::base(dist).nest("/api", api); cube_core::serve(app, 8080).await }