Webhook: back off + retry on 429, and report the real status
Discord rate-limits a webhook after a burst of sends. _upload_to_webhook
now honours the 429 retry_after and retries (up to 4×), so a batch of
images goes through instead of failing. The frontend also reports the
webhook's actual status (j.status) — previously it showed the route's
200 ("Send failed: HTTP 200"), masking the real 429.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+14
-2
@@ -59,13 +59,25 @@ def _resolve_image_path(filename, subfolder, type_):
|
||||
return target if os.path.isfile(target) else None
|
||||
|
||||
|
||||
async def _upload_to_webhook(webhook, filename, data, content=""):
|
||||
"""POST image bytes to a Discord webhook as multipart/form-data. Returns (ok, status, body)."""
|
||||
async def _upload_to_webhook(webhook, filename, data, content="", _attempt=0):
|
||||
"""POST image bytes to a Discord webhook (multipart). Respects 429 rate limits. Returns (ok, status, body)."""
|
||||
form = aiohttp.FormData()
|
||||
form.add_field("payload_json", json.dumps({"content": content}))
|
||||
form.add_field("files[0]", data, filename=filename, content_type="application/octet-stream")
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(webhook, data=form) as resp:
|
||||
if resp.status == 429 and _attempt < 4:
|
||||
# Discord rate-limited the webhook — wait the requested backoff and retry
|
||||
retry = 1.0
|
||||
try:
|
||||
retry = float((await resp.json()).get("retry_after", retry))
|
||||
except Exception:
|
||||
try:
|
||||
retry = float(resp.headers.get("Retry-After", retry))
|
||||
except Exception:
|
||||
pass
|
||||
await asyncio.sleep(min(retry + 0.25, 15))
|
||||
return await _upload_to_webhook(webhook, filename, data, content, _attempt + 1)
|
||||
return resp.status in (200, 204), resp.status, (await resp.text())[:300]
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -37,7 +37,8 @@ async function sendToDiscord(node) {
|
||||
});
|
||||
const j = await r.json().catch(() => ({}));
|
||||
if (j?.ok) toast("success", "Sent to Discord");
|
||||
else toast("error", "Send failed: " + (j?.error || ("HTTP " + r.status)));
|
||||
else if (j?.status === 429) toast("error", "Discord rate-limited the webhook — wait a moment and retry");
|
||||
else toast("error", "Send failed: " + (j?.error || ("HTTP " + (j?.status ?? r.status))));
|
||||
} catch (err) {
|
||||
toast("error", "Send failed: " + err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user