Refactor analyze recovery and worker busy status

The analyze recovery scan has been refactored to iterate through user
directories and enqueue pending analysis jobs more efficiently. The
`WorkerBusy` status has been introduced as an `Arc<AtomicBool>` to track
whether the analyze worker is currently processing a job.

This `WorkerBusy` flag is used in the `analyze::worker::run` function
and managed by a `BusyGuard` RAII struct, ensuring the flag is correctly
set and unset even in case of panics.

The `handle_my_cases` and `handle_case_detail` handlers in `user_web.rs`
now utilize the `WorkerBusy` flag to accurately display the "analyzing"
status and to trigger a self-heal of orphaned analysis inputs when the
worker is idle.

Additionally, the `WorkerBusy` type is now exported from
`server/src/lib.rs` to be accessible by other modules. The test cases
have been updated to include the `WorkerBusy` parameter when spawning
the analyze worker.
This commit is contained in:
2026-04-16 00:19:08 +02:00
parent 4e145dd167
commit 9072d7a833
7 changed files with 191 additions and 84 deletions
+15
View File
@@ -8,6 +8,7 @@ pub mod routes;
pub mod transcribe;
pub mod web_session;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use axum::extract::FromRef;
@@ -18,6 +19,12 @@ use config::Config;
use transcribe::TranscribeSender;
use web_session::SessionStore;
/// Live "is the analyze worker currently processing a job?" flag.
/// Set true before each `process()` call, false after. UI uses it to
/// distinguish a real in-flight analysis from a stale `analysis_input_v*.json`
/// orphan left over from a crash.
pub type WorkerBusy = Arc<AtomicBool>;
/// Shared application state. Clonable — all fields are cheap to clone
/// (`Arc` and `mpsc::Sender`).
#[derive(Clone)]
@@ -26,6 +33,7 @@ pub struct AppState {
pub transcribe_tx: TranscribeSender,
pub analyze_tx: AnalyzeSender,
pub session_store: SessionStore,
pub worker_busy: WorkerBusy,
}
impl FromRef<AppState> for Arc<Config> {
@@ -52,6 +60,12 @@ impl FromRef<AppState> for SessionStore {
}
}
impl FromRef<AppState> for WorkerBusy {
fn from_ref(state: &AppState) -> Self {
state.worker_busy.clone()
}
}
/// Test/simple entrypoint: jobs pushed into either channel are dropped
/// because the receivers are not retained. Use [`create_router_with_state`]
/// from `main.rs` where real workers own the receivers.
@@ -63,6 +77,7 @@ pub fn create_router(config: Arc<Config>) -> Router {
transcribe_tx,
analyze_tx,
session_store: web_session::new_store(),
worker_busy: Arc::new(AtomicBool::new(false)),
})
}