fix: retry 429 avec backoff + sérialisation uploadAll + 409 traité comme skipped

This commit is contained in:
2026-06-11 14:37:12 +02:00
parent 85b0590d85
commit fecf56ff09
2 changed files with 41 additions and 15 deletions
+7 -2
View File
@@ -249,8 +249,13 @@ export function useImages() {
[items, update],
)
const uploadAll = useCallback(() => {
items.filter((i) => i.status === 'ready').forEach((i) => uploadOne(i.id))
const uploadAll = useCallback(async () => {
const ready = items.filter((i) => i.status === 'ready')
for (const item of ready) {
await uploadOne(item.id)
// Pause de 500ms entre chaque upload pour éviter le rate limit Shopify
await new Promise(r => setTimeout(r, 500))
}
}, [items, uploadOne])
const removeItem = useCallback((id: string) => {
+34 -13
View File
@@ -118,20 +118,41 @@ export async function uploadProductImage(
const existingUrl = await productImageExists(shopifyProductId, filename)
if (existingUrl) return { url: existingUrl, skipped: true }
const res = await fetch(`${baseUrl}/products/${shopifyProductId}/images.json`, {
method: 'POST',
headers,
body: JSON.stringify({ image: { attachment: imageBase64, filename } }),
})
// Retry avec backoff exponentiel (gère le 429 rate limit)
const MAX_RETRIES = 4
let delay = 1000
if (!res.ok) {
const body = await res.text()
throw new Error(`Shopify upload error: ${res.status}${body}`)
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
const res = await fetch(`${baseUrl}/products/${shopifyProductId}/images.json`, {
method: 'POST',
headers,
body: JSON.stringify({ image: { attachment: imageBase64, filename } }),
})
// 409 Conflict = image déjà présente → traiter comme skipped
if (res.status === 409) {
return { url: `https://placeholder/already-exists/${filename}`, skipped: true }
}
// 429 Too Many Requests → attendre et réessayer
if (res.status === 429 && attempt < MAX_RETRIES) {
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '0', 10)
await new Promise(r => setTimeout(r, retryAfter > 0 ? retryAfter * 1000 : delay))
delay *= 2
continue
}
if (!res.ok) {
const body = await res.text()
throw new Error(`Shopify upload error: ${res.status}${body}`)
}
const data = await res.json()
if (!data.image?.src) {
throw new Error('Shopify response invalide : champ image.src manquant')
}
return { url: data.image.src as string }
}
const data = await res.json()
if (!data.image?.src) {
throw new Error('Shopify response invalide : champ image.src manquant')
}
return { url: data.image.src as string }
throw new Error('Shopify upload error: trop de tentatives (rate limit persistant)')
}