Fix: Persona Polling Issue

This commit is contained in:
ajaysi
2025-10-12 14:27:15 +05:30
parent 2a3ad8addc
commit 08ce9588f4
5 changed files with 75 additions and 20 deletions

View File

@@ -19,7 +19,8 @@ export interface PersonaTaskStatus {
export interface UsePersonaPollingOptions {
interval?: number; // Polling interval in milliseconds
maxAttempts?: number; // Maximum number of polling attempts
maxAttempts?: number; // Maximum number of polling attempts (default: 180 = 6 minutes at 2s interval)
maxDuration?: number; // Maximum polling duration in milliseconds (default: 10 minutes)
onProgress?: (message: string, progress: number) => void; // Callback for progress updates
onComplete?: (result: any) => void; // Callback when task completes
onError?: (error: string) => void; // Callback when task fails
@@ -40,6 +41,8 @@ export interface UsePersonaPollingReturn {
export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePersonaPollingReturn {
const {
interval = 2000, // 2 seconds default
maxAttempts = 180, // 6 minutes at 2s interval
maxDuration = 600000, // 10 minutes in milliseconds
onProgress,
onComplete,
onError
@@ -67,6 +70,9 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
const intervalRef = useRef<NodeJS.Timeout | null>(null);
const attemptsRef = useRef(0);
const currentTaskIdRef = useRef<string | null>(null);
const startTimeRef = useRef<number>(0);
const stuckProgressRef = useRef<number>(0);
const stuckCountRef = useRef<number>(0);
const stopPolling = useCallback(() => {
console.log('stopPersonaPolling called');
@@ -78,6 +84,9 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
setIsPolling(false);
attemptsRef.current = 0;
currentTaskIdRef.current = null;
startTimeRef.current = 0;
stuckProgressRef.current = 0;
stuckCountRef.current = 0;
}, []);
const startPolling = useCallback((taskId: string) => {
@@ -97,6 +106,9 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
setResult(null);
setError(null);
attemptsRef.current = 0;
startTimeRef.current = Date.now();
stuckProgressRef.current = 0;
stuckCountRef.current = 0;
const poll = async () => {
if (!currentTaskIdRef.current) {
@@ -104,6 +116,25 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
return;
}
// Check max attempts
if (attemptsRef.current >= maxAttempts) {
console.error('Persona polling: Max attempts reached');
setError('Persona generation timed out - please try again later');
onError?.('Persona generation timed out after maximum attempts');
stopPolling();
return;
}
// Check max duration
const elapsed = Date.now() - startTimeRef.current;
if (elapsed >= maxDuration) {
console.error('Persona polling: Max duration reached');
setError('Persona generation timed out - please try again later');
onError?.('Persona generation exceeded maximum duration');
stopPolling();
return;
}
try {
const response = await apiClient.get(`/api/onboarding/step4/persona-task/${currentTaskIdRef.current}`);
const status: PersonaTaskStatus = response.data;
@@ -113,6 +144,21 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
setProgress(status.progress);
setCurrentStep(status.current_step);
// Detect stuck progress (same progress for 20+ consecutive polls = ~40 seconds)
if (status.progress === stuckProgressRef.current) {
stuckCountRef.current++;
if (stuckCountRef.current >= 20) {
console.error('Persona polling: Progress stuck at', status.progress, 'for too long');
setError('Persona generation appears stuck - please try again or contact support');
onError?.('Persona generation stuck - no progress for extended period');
stopPolling();
return;
}
} else {
stuckProgressRef.current = status.progress;
stuckCountRef.current = 0;
}
// Update progress messages
if (status.progress_messages && status.progress_messages.length > 0) {
console.log('Progress messages received:', status.progress_messages);
@@ -154,7 +200,7 @@ export function usePersonaPolling(options: UsePersonaPollingOptions = {}): UsePe
// Start polling immediately, then at intervals
poll();
intervalRef.current = setInterval(poll, interval);
}, [isPolling, interval, onProgress, onComplete, onError, stopPolling]);
}, [isPolling, interval, maxAttempts, maxDuration, onProgress, onComplete, onError, stopPolling]);
// Cleanup on unmount
useEffect(() => {