mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 21:11:12 -05:00
feat: Implement retry logic for composite submissions
This commit is contained in:
@@ -370,40 +370,98 @@ async function submitCompositeCreation(
|
||||
}
|
||||
}
|
||||
|
||||
// Use RPC to create submission with items atomically
|
||||
const { data: result, error } = await supabase.rpc('create_submission_with_items', {
|
||||
p_user_id: userId,
|
||||
p_submission_type: uploadedPrimary.type,
|
||||
p_content: { action: 'create' } as unknown as Json,
|
||||
p_items: submissionItems as unknown as Json[]
|
||||
});
|
||||
// Use RPC to create submission with items atomically with retry logic
|
||||
const { withRetry } = await import('./retryHelpers');
|
||||
const { toast } = await import('@/hooks/use-toast');
|
||||
|
||||
const result = await withRetry(
|
||||
async () => {
|
||||
const { data, error } = await supabase.rpc('create_submission_with_items', {
|
||||
p_user_id: userId,
|
||||
p_submission_type: uploadedPrimary.type,
|
||||
p_content: { action: 'create' } as unknown as Json,
|
||||
p_items: submissionItems as unknown as Json[]
|
||||
});
|
||||
|
||||
if (error) {
|
||||
// Extract Supabase error details for better error logging
|
||||
const supabaseError = error as { message?: string; code?: string; details?: string; hint?: string };
|
||||
const errorMessage = supabaseError.message || 'Unknown error';
|
||||
const errorCode = supabaseError.code;
|
||||
const errorDetails = supabaseError.details;
|
||||
const errorHint = supabaseError.hint;
|
||||
|
||||
// Create proper Error instance with enhanced context
|
||||
const enhancedError = new Error(
|
||||
`Composite submission failed: ${errorMessage}${errorDetails ? `\nDetails: ${errorDetails}` : ''}${errorHint ? `\nHint: ${errorHint}` : ''}`
|
||||
);
|
||||
|
||||
handleError(enhancedError, {
|
||||
if (error) {
|
||||
// Extract Supabase error details for better error logging
|
||||
const supabaseError = error as { message?: string; code?: string; details?: string; hint?: string };
|
||||
const errorMessage = supabaseError.message || 'Unknown error';
|
||||
const errorCode = supabaseError.code;
|
||||
const errorDetails = supabaseError.details;
|
||||
const errorHint = supabaseError.hint;
|
||||
|
||||
// Create proper Error instance with enhanced context
|
||||
const enhancedError = new Error(
|
||||
`Composite submission failed: ${errorMessage}${errorDetails ? `\nDetails: ${errorDetails}` : ''}${errorHint ? `\nHint: ${errorHint}` : ''}`
|
||||
);
|
||||
|
||||
// Attach Supabase metadata for retry logic
|
||||
(enhancedError as any).supabaseCode = errorCode;
|
||||
(enhancedError as any).supabaseDetails = errorDetails;
|
||||
(enhancedError as any).supabaseHint = errorHint;
|
||||
|
||||
throw enhancedError;
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
{
|
||||
maxAttempts: 3,
|
||||
baseDelay: 1000,
|
||||
maxDelay: 10000,
|
||||
onRetry: (attempt, error, delay) => {
|
||||
logger.warn('Retrying composite submission', {
|
||||
attempt,
|
||||
maxAttempts: 3,
|
||||
delay,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
primaryType: uploadedPrimary.type,
|
||||
dependencyCount: dependencies.length
|
||||
});
|
||||
|
||||
// Show user feedback
|
||||
toast({
|
||||
title: 'Submission retry',
|
||||
description: `Attempt ${attempt}/3 - Retrying in ${Math.round(delay / 1000)}s...`,
|
||||
});
|
||||
},
|
||||
shouldRetry: (error) => {
|
||||
// Don't retry validation errors
|
||||
if (error instanceof Error) {
|
||||
const message = error.message.toLowerCase();
|
||||
if (message.includes('required')) return false;
|
||||
if (message.includes('banned')) return false;
|
||||
if (message.includes('suspended')) return false;
|
||||
if (message.includes('slug')) return false;
|
||||
if (message.includes('already exists')) return false;
|
||||
if (message.includes('duplicate')) return false;
|
||||
if (message.includes('permission')) return false;
|
||||
if (message.includes('forbidden')) return false;
|
||||
if (message.includes('unauthorized')) return false;
|
||||
}
|
||||
|
||||
// Use default retryable error detection from retryHelpers
|
||||
const { isRetryableError } = require('./retryHelpers');
|
||||
return isRetryableError(error);
|
||||
}
|
||||
}
|
||||
).catch((error) => {
|
||||
// Final failure - log and throw
|
||||
handleError(error, {
|
||||
action: 'Composite submission',
|
||||
metadata: {
|
||||
primaryType: uploadedPrimary.type,
|
||||
dependencyCount: dependencies.length,
|
||||
supabaseCode: errorCode,
|
||||
supabaseDetails: errorDetails,
|
||||
supabaseHint: errorHint
|
||||
supabaseCode: (error as any).supabaseCode,
|
||||
supabaseDetails: (error as any).supabaseDetails,
|
||||
supabaseHint: (error as any).supabaseHint,
|
||||
retriesExhausted: true
|
||||
},
|
||||
});
|
||||
|
||||
throw enhancedError;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
|
||||
return { submitted: true, submissionId: result };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user