Treat REST and the Gateway separately
REST requests perform actions such as sending messages. The Gateway is a persistent connection that delivers events. They have different limits and failure modes, so one generic retry loop is not enough.
REST requests
Gateway sessions
Use the response to decide what to do
| Signal | Meaning | Next step |
|---|---|---|
| X-RateLimit-Remaining | Requests left in this bucket | Queue further work as the bucket runs out |
| X-RateLimit-Reset-After | Time until the bucket resets | Use the returned interval |
| X-RateLimit-Bucket | Identifier for a rate-limit bucket | Let the client group requests correctly |
| 429 with retry_after | The request hit a limit | Wait for the stated delay; respect global scope |
| 401 or 403 | Authentication or permission problem | Fix the cause; do not retry indefinitely |
Discord documents these signals in its rate-limit reference. Do not hardcode a request rate from an old example. Limits can differ by route and change over time.
Network failures need more care: if a request times out, the action may still have happened. Use idempotency where supported and reconcile the result before repeating an action that could create duplicate messages or rewards.
Keep the connection responsive
Discord supplies the heartbeat interval in Hello. The first heartbeat uses a random offset; later heartbeats follow the interval. Missing acknowledgments should lead to reconnect handling. Prefer the library’s implementation to a hand-written timer.
When a fresh Identify is needed, respect the session start limits and concurrency returned by Get Gateway Bot. Resume an existing session when possible. See Discord’s Gateway documentation for the connection lifecycle.
a common cause of disconnects
Slow work can block a healthy connection.
Move CPU-heavy image processing, long synchronous loops, and large exports out of the Gateway process. Adding more reconnect attempts will not fix a blocked event loop.
Use bounded retries for temporary failures
For your own background jobs, exponential backoff with jitter spreads retries out. This helper chooses a delay; it does not replace Discord’s rate-limit handling.
Set a timeout for each attempt and a total retry budget. Stop on permanent errors. If the queue keeps growing, reduce incoming work or add capacity instead of endlessly delaying the same jobs.
Watch a few useful signals
- Rate-limit responses by route, without logging authorization headers.
- Command latency and errors during busy periods.
- Heartbeat acknowledgment delays and reconnect frequency.
- Identify attempts and remaining session starts.
- Queue length, oldest job age, and repeated job failures.
Correlate these signals with deployments and traffic spikes. Test disconnect recovery on a test bot before changing reconnect behavior in production. For larger workloads, see scaling and sharding.