From e0f5d39837d11b5f5a6d357c7f9d333bde4d55fa Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Tue, 28 Apr 2026 07:02:43 -0700 Subject: [PATCH] fix(discord): widen slash-sync timeout to 600s under rate-limit pressure (#16713) (#17029) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discord's per-app command-management bucket is ~5 writes / 20 s. A mass-prune-plus-upsert reconcile (77 orphans + 30 desired = 107 writes in the reported case) can't finish under the old flat 30 s budget, and the subsequent reconnect retries inside the rate-limit cooldown also time out — leaving slash commands broken for ~60 min until the bucket fully recovers. Bump the timeout to 600 s so realistic bursts drain, update the warning message to point at the saturated bucket instead of a hardcoded 30 s. The 600 s cap still guards against a true hang. Credit to @Tranquil-Flow for PR #16739 and @davidbordenwi for reporting #16713 with the bucket-math diagnosis. Closes #16713. Co-authored-by: Teknium --- gateway/platforms/discord.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index 903624a166..2e08d77c68 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -813,7 +813,14 @@ class DiscordAdapter(BasePlatformAdapter): logger.info("[%s] Synced %d slash command(s) via bulk tree sync", self.name, len(synced)) return - summary = await asyncio.wait_for(self._safe_sync_slash_commands(), timeout=30) + # Discord's per-app command-management bucket is ~5 writes / 20 s, + # so a mass-prune-plus-upsert reconcile (e.g. 77 orphans + 30 + # desired = 107 writes) takes several minutes of forced waits. + # A flat 30 s budget blew up reliably under bucket pressure and + # left slash commands broken for ~60 min until the bucket fully + # recovered. Use a wide ceiling; the cap still guards against a + # true hang. (#16713) + summary = await asyncio.wait_for(self._safe_sync_slash_commands(), timeout=600) logger.info( "[%s] Safely reconciled %d slash command(s): unchanged=%d updated=%d recreated=%d created=%d deleted=%d", self.name, @@ -825,7 +832,11 @@ class DiscordAdapter(BasePlatformAdapter): summary["deleted"], ) except asyncio.TimeoutError: - logger.warning("[%s] Slash command sync timed out after 30s", self.name) + logger.warning( + "[%s] Slash command sync timed out — Discord rate-limit bucket " + "may be saturated; will retry on next reconnect", + self.name, + ) except asyncio.CancelledError: raise except Exception as e: # pragma: no cover - defensive logging