import { useEffect, useRef, useState } from "react"; import { api } from "../api"; import type { Job } from "../types"; // Poll a background job until it finishes, tolerant of transient poll failures (a single failed // request must not freeze progress — see the load-bar fix). Give up only after a run of failures. export function useJobPolling(jobId: string | null, onDone?: (job: Job) => void): Job | null { const [job, setJob] = useState(null); const onDoneRef = useRef(onDone); onDoneRef.current = onDone; useEffect(() => { if (!jobId) { setJob(null); return; } let stopped = false; let fails = 0; const t = setInterval(async () => { if (stopped) return; try { const next = await api.getJob(jobId); fails = 0; setJob(next); if (next.status === "done" || next.status === "error") { stopped = true; clearInterval(t); if (next.status === "done") onDoneRef.current?.(next); } } catch { fails += 1; if (fails >= 20) { // ~10s of consecutive failures — treat the job as unreachable. stopped = true; clearInterval(t); setJob((j) => j ? { ...j, status: "error", error: "Lost connection to the job." } : { id: jobId, type: "", status: "error", progress: {}, result: null, error: "Lost connection to the job.", created_at: "", } ); } // otherwise keep polling: the job is still running server-side. } }, 500); return () => { stopped = true; clearInterval(t); }; }, [jobId]); return job; }