feature/rbac y perfiles implementados
This commit is contained in:
99
src/hooks/usePollTaskStatus.js
Normal file
99
src/hooks/usePollTaskStatus.js
Normal file
@@ -0,0 +1,99 @@
|
||||
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 };
|
||||
}
|
||||
Reference in New Issue
Block a user