99 lines
2.8 KiB
JavaScript
99 lines
2.8 KiB
JavaScript
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 };
|
|
} |