import { useState, useRef, useCallback } from 'react'; import { fetchWithAuth } from '../fetchWithAuth'; const API_BASE_URL = import.meta.env.VITE_EFC_API_URL; // Estados que indican que la tarea ya terminó (no hay más que esperar) const FINAL_STATES = new Set(['SUCCESS', 'FAILURE', 'completed', 'failed', 'cancelled']); /** * Polling acotado de estado de tarea. * * Uso: * const { taskState, polling, poll, reset } = usePollTaskStatus({ maxAttempts: 3, intervalMs: 2500 }); * * // Después de enviar la tarea al microservicio: * poll(taskId); * * // taskState: null | { status, message, error, attempts } * // polling: true mientras hay intentos pendientes */ export function usePollTaskStatus({ maxAttempts = 3, intervalMs = 2500 } = {}) { const [taskState, setTaskState] = useState(null); const [polling, setPolling] = useState(false); const timeoutRef = useRef(null); const abortedRef = useRef(false); const attemptsRef = useRef(0); const stop = useCallback(() => { abortedRef.current = true; if (timeoutRef.current) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } setPolling(false); }, []); const reset = useCallback(() => { stop(); setTaskState(null); attemptsRef.current = 0; }, [stop]); const poll = useCallback((taskId) => { if (!taskId) return; // Reiniciar estado previo abortedRef.current = false; attemptsRef.current = 0; setPolling(true); setTaskState({ status: 'PENDING', message: null, error: null, attempts: 0 }); const attempt = async () => { if (abortedRef.current) return; attemptsRef.current += 1; const n = attemptsRef.current; try { const res = await fetchWithAuth(`${API_BASE_URL}/tasks/status/${taskId}/`); if (abortedRef.current) return; if (!res.ok) { setTaskState({ status: 'FAILURE', message: `Error HTTP ${res.status}`, error: true, attempts: n }); setPolling(false); return; } const data = await res.json(); if (abortedRef.current) return; const newState = { status: data.status, message: data.message || data.error || null, error: data.error || null, result: data.result || null, attempts: n, }; setTaskState(newState); if (FINAL_STATES.has(data.status) || n >= maxAttempts) { setPolling(false); return; } timeoutRef.current = setTimeout(attempt, intervalMs); } catch (err) { if (abortedRef.current) return; setTaskState({ status: 'FAILURE', message: err.message, error: true, attempts: n }); setPolling(false); } }; attempt(); }, [maxAttempts, intervalMs]); return { taskState, polling, poll, stop, reset }; }