Batch analyze jobs never time out - stuck in 'running' forever

Resolved 💬 2 comments Opened Jan 13, 2026 by edie-01 Closed Feb 27, 2026

Summary

Batch analyze jobs (batch_analyze_content) never time out, causing them to stay in "running" status indefinitely if the processing thread fails or hangs.

Evidence

Job 8d17b004 has been running for 45+ hours:

8d17b004-fcd7-4ff3-830c-33280d151de4|batch_analyze_content|running|2026-01-11T18:36:39
Progress: 0/3 completed, 0 failed

The job's temp directory exists but is empty - no results were ever written, indicating the processing thread failed silently.

Root Cause

poll_batch_job() in caltools/src/jobs/mod.rs does not implement timeout checking:

// Line 583-587 in calui/src/jobs/mod.rs
let outcome = if job.job_type == JOB_TYPE_BATCH_ANALYZE {
    poll_batch_job(&store, job)  // ← No timeout check!
} else {
    poll_single_job(&store, job)  // ← Has timeout via poll_job_impl()
};

poll_single_job() calls poll_job_impl() which has timeout logic (lines 346-366):

// Check for timeout before polling external service
let max_duration = job_impl.max_duration();
if job_record.elapsed() > max_duration {
    store.mark_failed(job_id, &error)?;
    return Ok(PollOutcome::Failed { ... });
}

But poll_batch_job() is a completely separate code path that skips this check.

Impact

  • Batch jobs stuck in "running" forever consume UI resources (polled every 5 seconds)
  • Users see stale "running" jobs that will never complete
  • No error feedback to agent when batch analysis fails

Fix

Add timeout check to poll_batch_job(), matching the logic in poll_job_impl():

pub fn poll_batch_job(store: &JobStore, job: &JobRecord) -> crate::Result<PollOutcome> {
    // ... existing code ...

    // ADD: Check for timeout before processing
    let max_duration = Duration::from_secs(900); // 15 minutes, or use batch_job.max_duration()
    if job.elapsed() > max_duration {
        let error = format!("Job timed out after {}", job.elapsed_string());
        store.mark_failed(&job_id, &error)?;
        return Ok(PollOutcome::Failed { job_id, job_type, error });
    }

    // ... rest of existing code ...
}

Files

  • caltools/src/jobs/mod.rs - poll_batch_job() function (lines 508-598)
  • calui/src/jobs/mod.rs - Calls poll_batch_job() (line 584)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗