agent: code-atomiser-fix — cancellable Whisper inference + bounded drain + lock-over-await
Three findings chain: thread::spawn discarded the JoinHandle and gave no cancellation route into the whisper backend; drain_inference busy- polled with no timeout; stop_live_transcription_session held the lifecycle AsyncMutex across the await of a non-cancellable spawn_blocking handle. Together: a single wedged inference (ggml deadlock, GPU stall) bricked every future start/stop until app restart. Fix: each inference task carries an Arc<AtomicBool> abort_flag; the flag is wired into whisper-rs::FullParams::set_abort_callback_safe so the spawned blocking thread checks it and exits cleanly. drain_inference is bounded by a deadline (3 x chunk_duration, min 2s); on expiry the flag is set, the receiver is dropped, and a typed Error::InferenceTimeout status is surfaced. Drop for InferenceTask asserts the abort flag so any '?'-propagation or panic unwind closes the cancellation route without relying on the explicit drain path. stop_live_transcription_session restructured so the lifecycle guard is dropped BEFORE the JoinHandle is awaited; start_live_transcription_session releases the guard explicitly after installing the RunningLiveSession. Unit test added: dropping_inference_task_sets_abort_flag covers the Race-A regression directly. A real Race-B drain-timeout test would require a wedged whisper-rs, which is hard to fixture; that path is covered by the SAFETY comment and cargo build + manual smoke. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,14 @@ pub enum Error {
|
||||
#[error("transcription failed: {0}")]
|
||||
TranscriptionFailed(String),
|
||||
|
||||
/// Inference exceeded the bounded wait imposed by the caller (live
|
||||
/// session `drain_inference`). The spawned worker has had its abort
|
||||
/// flag set so whisper-rs will return early on its next
|
||||
/// abort-callback poll; the lock-up itself is *not* recovered by
|
||||
/// this error — but the live-session lifecycle can now progress.
|
||||
#[error("inference timed out after {timeout_ms}ms")]
|
||||
InferenceTimeout { timeout_ms: u64 },
|
||||
|
||||
#[error("audio decode failed: {0}")]
|
||||
AudioDecodeFailed(String),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user