feat: Implement retry logic for composite submissions

This commit is contained in:
gpt-engineer-app[bot]
2025-11-05 13:16:30 +00:00
parent 876119c079
commit 5e0640252c
3 changed files with 288 additions and 32 deletions

View File

@@ -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 };
}