feat: add auto-retry (3 attempts) for file uploads on flaky connections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt
2026-04-07 20:10:52 -04:00
parent 97d7f9b625
commit 158eba416d

View File

@@ -166,26 +166,46 @@ export function RequirementUploadSlot({
requirementId: requirement.id, requirementId: requirement.id,
}) })
// Upload file with progress tracking // Upload file with progress tracking and auto-retry
await new Promise<void>((resolve, reject) => { const maxRetries = 3
const xhr = new XMLHttpRequest() for (let attempt = 1; attempt <= maxRetries; attempt++) {
xhr.upload.addEventListener('progress', (event) => { try {
if (event.lengthComputable) { await new Promise<void>((resolve, reject) => {
setProgress(Math.round((event.loaded / event.total) * 100)) const xhr = new XMLHttpRequest()
} xhr.upload.addEventListener('progress', (event) => {
}) if (event.lengthComputable) {
xhr.addEventListener('load', () => { setProgress(Math.round((event.loaded / event.total) * 100))
if (xhr.status >= 200 && xhr.status < 300) { }
resolve() })
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve()
} else {
reject(new Error(`Upload failed with status ${xhr.status}`))
}
})
xhr.addEventListener('error', () =>
reject(new Error('Network error during upload'))
)
xhr.addEventListener('abort', () =>
reject(new Error('Upload was aborted'))
)
xhr.open('PUT', url)
xhr.setRequestHeader('Content-Type', file.type)
xhr.send(file)
})
break // Success — exit retry loop
} catch (uploadErr) {
if (attempt < maxRetries) {
const delay = attempt * 2000
toast.info(`Upload interrupted, retrying... (${attempt}/${maxRetries})`)
setProgress(0)
await new Promise((r) => setTimeout(r, delay))
} else { } else {
reject(new Error(`Upload failed with status ${xhr.status}`)) throw uploadErr
} }
}) }
xhr.addEventListener('error', () => reject(new Error('Upload failed'))) }
xhr.open('PUT', url)
xhr.setRequestHeader('Content-Type', file.type)
xhr.send(file)
})
// Save metadata // Save metadata
await saveFileMetadata.mutateAsync({ await saveFileMetadata.mutateAsync({