Skip to content

fix: handle Discord typing indicator 429 gracefully - #22398

Closed
nycomar wants to merge 1 commit into
NousResearch:mainfrom
nycomar:fix/discord-typing-429-backoff
Closed

fix: handle Discord typing indicator 429 gracefully#22398
nycomar wants to merge 1 commit into
NousResearch:mainfrom
nycomar:fix/discord-typing-429-backoff

Conversation

@nycomar

@nycomar nycomar commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

The typing indicator loop (send_typing) ran every 8s and died on any
exception, including Discord 429 rate limits. Once a 429 killed the
loop, the indicator never restarted — and the raw exception bounce
could cascade into broader gateway instability.

Changes

  • Bump sleep from 8s → 12s (typing light lasts ~10s, so 12s keeps
    the indicator mostly continuous with less endpoint pressure)
  • 429 backoff — on rate limit, extract retry_after from the
    exception, log a warning, sleep the backoff, and continue the loop
  • Non-rate-limit errors — still log debug and return (unchanged)

Test Plan

  • Verified syntax: python3 -c "import ast; ast.parse(...)"
  • Manual: run gateway, observe typing indicator survival under
    concurrent channel load

Closes #N/A

The typing indicator loop (send_typing) ran every 8s and died on any
exception, including Discord 429 rate limits.  Once a 429 killed the
loop, the indicator never restarted — and the raw exception bounce
could cascade into broader gateway instability.

Changes:
- Bump sleep interval from 8s to 12s (typing light lasts ~10s)
- On 429: extract retry_after, log a warning, sleep the backoff,
  and continue the loop
- On non-rate-limit errors: log debug and return (unchanged
  behaviour)
Copilot AI review requested due to automatic review settings May 9, 2026 08:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates DiscordAdapter.send_typing() to make the Discord typing-indicator background loop more resilient, specifically to avoid permanently losing the typing indicator when Discord rate-limits the typing endpoint.

Changes:

  • Increased typing refresh cadence from 8s to 12s to reduce endpoint pressure while keeping the indicator mostly continuous.
  • Added rate-limit-aware handling in the typing loop: attempt to extract retry_after, sleep, and continue rather than exiting immediately.
  • Expanded docstring to describe the intended rate-limit behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2677 to +2680
Rate-limit handling: if a 429 is encountered, the loop logs a
warning, sleeps for the ``retry_after`` duration (or a sensible
default), and continues — it does NOT die on a single rate-limit
hit. Only CancelledError (from stop_typing) stops the loop.
Comment on lines +2700 to +2714
# Don't die on 429 — backoff and continue
retry_after = self._extract_discord_retry_after(e)
if retry_after is not None:
logger.warning(
"Typing indicator rate-limited for %s; retrying in %.1fs",
chat_id, retry_after,
)
else:
logger.debug(
"Discord typing indicator failed for %s: %s",
chat_id, e,
)
return
await asyncio.sleep(retry_after)
continue
Comment on lines +2707 to +2713
else:
logger.debug(
"Discord typing indicator failed for %s: %s",
chat_id, e,
)
return
await asyncio.sleep(retry_after)
Comment on lines +2700 to +2715
# Don't die on 429 — backoff and continue
retry_after = self._extract_discord_retry_after(e)
if retry_after is not None:
logger.warning(
"Typing indicator rate-limited for %s; retrying in %.1fs",
chat_id, retry_after,
)
else:
logger.debug(
"Discord typing indicator failed for %s: %s",
chat_id, e,
)
return
await asyncio.sleep(retry_after)
continue
await asyncio.sleep(12)
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/discord Discord bot adapter labels May 9, 2026
@nycomar

nycomar commented May 10, 2026

Copy link
Copy Markdown
Contributor Author

Just a note from deploying this fix —

The typing indicator 429 handling works great. Logs show graceful retries instead of crashes, no issues there.

One thing I ran into though — on my setup the gateway got stuck in a restart loop. When --replace sends SIGTERM to the old process, it exits clean with code 0, and Restart=always in the systemd unit immediately respawns. The new instance starts with --replace again, kills whatever is running, and the cycle repeats.

I switched it to Restart=on-failure in the unit file. Crashes still restart automatically, but planned clean exits don't trigger another respawn. That killed the loop.

Just make sure to keep --replace in ExecStart — you need it for stale pid files after crashes. It's only the Restart=always bit that needs changing.

@teknium1

Copy link
Copy Markdown
Contributor

Merged via #29671 — your commit be0728cac was cherry-picked onto current main with your authorship preserved in git log. Thanks @nycomar for the catch + fix!

@nycomar

nycomar commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

Merged via #29671 — your commit be0728cac was cherry-picked onto current main with your authorship preserved in git log. Thanks @nycomar for the catch + fix!

My pleasure!

If i find any other issues, I'll contribute again! Happy to help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants