fix: add rate limiting with retry on 429 in sync-stock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,19 +80,28 @@ export async function POST(req: NextRequest) {
|
|||||||
let updated = 0
|
let updated = 0
|
||||||
let errors = 0
|
let errors = 0
|
||||||
|
|
||||||
|
const sleep = (ms: number) => new Promise(r => setTimeout(r, ms))
|
||||||
|
|
||||||
|
const shopifyFetch = async (url: string, opts: RequestInit, retries = 3): Promise<Response> => {
|
||||||
|
const res = await fetch(url, opts)
|
||||||
|
if (res.status === 429 && retries > 0) {
|
||||||
|
const retryAfter = parseInt(res.headers.get('Retry-After') ?? '2', 10)
|
||||||
|
await sleep(retryAfter * 1000)
|
||||||
|
return shopifyFetch(url, opts, retries - 1)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
for (let i = 0; i < entries.length; i++) {
|
||||||
const { shopifyId, stock, title } = entries[i]
|
const { shopifyId, stock, title } = entries[i]
|
||||||
send({ type: 'progress', current: i + 1, total: entries.length, title })
|
send({ type: 'progress', current: i + 1, total: entries.length, title })
|
||||||
try {
|
try {
|
||||||
// Récupérer le variant pour obtenir inventory_item_id
|
await sleep(300) // éviter le rate limiting (2 req/s max)
|
||||||
const pRes = await fetch(`${baseUrl}/products/${shopifyId}.json?fields=variants`, { headers })
|
|
||||||
if (pRes.status === 404) {
|
const pRes = await shopifyFetch(`${baseUrl}/products/${shopifyId}.json?fields=variants`, { headers })
|
||||||
// Produit supprimé de Shopify, on ignore silencieusement
|
if (pRes.status === 404) continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (!pRes.ok) {
|
if (!pRes.ok) {
|
||||||
const msg = `Produit ${shopifyId} erreur (${pRes.status})`
|
send({ type: 'error', title, message: `Produit ${shopifyId} erreur (${pRes.status})` })
|
||||||
send({ type: 'error', title, message: msg })
|
|
||||||
errors++
|
errors++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -100,13 +109,14 @@ export async function POST(req: NextRequest) {
|
|||||||
const inventoryItemId = pData.product.variants[0]?.inventory_item_id
|
const inventoryItemId = pData.product.variants[0]?.inventory_item_id
|
||||||
if (!inventoryItemId) { errors++; continue }
|
if (!inventoryItemId) { errors++; continue }
|
||||||
|
|
||||||
// Connect (idempotent)
|
await sleep(300)
|
||||||
await fetch(`${baseUrl}/inventory_levels/connect.json`, {
|
await shopifyFetch(`${baseUrl}/inventory_levels/connect.json`, {
|
||||||
method: 'POST', headers,
|
method: 'POST', headers,
|
||||||
body: JSON.stringify({ location_id: locationId, inventory_item_id: inventoryItemId }),
|
body: JSON.stringify({ location_id: locationId, inventory_item_id: inventoryItemId }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const setRes = await fetch(`${baseUrl}/inventory_levels/set.json`, {
|
await sleep(300)
|
||||||
|
const setRes = await shopifyFetch(`${baseUrl}/inventory_levels/set.json`, {
|
||||||
method: 'POST', headers,
|
method: 'POST', headers,
|
||||||
body: JSON.stringify({ location_id: locationId, inventory_item_id: inventoryItemId, available: stock }),
|
body: JSON.stringify({ location_id: locationId, inventory_item_id: inventoryItemId, available: stock }),
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user