feat: implement exponential backoff and retry logic for file uploads

This commit is contained in:
averel10
2026-03-13 10:07:43 +01:00
parent d8a7fdf1f0
commit 209ca6a6c0

View File

@@ -113,6 +113,42 @@ export default function UploadDatasetEntriesModal({
file: File, file: File,
index: number, index: number,
queue: Array<{ file: File; status: 'pending' | 'uploading' | 'completed' | 'failed'; progress: number; message?: string }> queue: Array<{ file: File; status: 'pending' | 'uploading' | 'completed' | 'failed'; progress: number; message?: string }>
): Promise<{ tempDir: string }> {
const MAX_RETRIES = 3;
return (async () => {
let lastError: Error | null = null;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
const result = await uploadAttempt(file, index, queue, attempt, MAX_RETRIES);
return result;
} catch (error) {
lastError = error instanceof Error ? error : new Error('Unknown error');
if (attempt < MAX_RETRIES) {
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt - 1) * 1000;
queue[index].message = `Retrying in ${delay / 1000}s... (attempt ${attempt}/${MAX_RETRIES})`;
setUploadQueue([...queue]);
await new Promise(resolve => setTimeout(resolve, delay));
queue[index].progress = 0; // Reset progress for next attempt
setUploadQueue([...queue]);
}
}
}
throw lastError || new Error('Upload failed after all retries');
})();
}
function uploadAttempt(
file: File,
index: number,
queue: Array<{ file: File; status: 'pending' | 'uploading' | 'completed' | 'failed'; progress: number; message?: string }>,
attempt: number,
maxRetries: number
): Promise<{ tempDir: string }> { ): Promise<{ tempDir: string }> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const formData = new FormData(); const formData = new FormData();
@@ -126,6 +162,9 @@ export default function UploadDatasetEntriesModal({
if (event.lengthComputable) { if (event.lengthComputable) {
const progress = Math.round((event.loaded / event.total) * 100); const progress = Math.round((event.loaded / event.total) * 100);
queue[index].progress = progress; queue[index].progress = progress;
if (attempt > 1) {
queue[index].message = `Uploading (retry ${attempt}/${maxRetries})`;
}
setUploadQueue([...queue]); setUploadQueue([...queue]);
} }
}); });
@@ -153,7 +192,7 @@ export default function UploadDatasetEntriesModal({
}); });
xhr.addEventListener('error', () => { xhr.addEventListener('error', () => {
reject(new Error('Upload failed')); reject(new Error('Network error'));
}); });
xhr.addEventListener('abort', () => { xhr.addEventListener('abort', () => {