engineering

Discord Rate Limits and Gateway Reliability

Rank.top Team4 min read

Handle REST limits, reconnects, and slow work without retry storms or missed heartbeats.

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

Let your Discord library queue requests by route and handle rate-limit responses. Coordinate traffic if several processes share the same bot token.

Gateway sessions

Use the library’s heartbeat, reconnect, and resume support. Keep the event loop free so those tasks can run on time.

Use the response to decide what to do

SignalMeaningNext step
X-RateLimit-RemainingRequests left in this bucketQueue further work as the bucket runs out
X-RateLimit-Reset-AfterTime until the bucket resetsUse the returned interval
X-RateLimit-BucketIdentifier for a rate-limit bucketLet the client group requests correctly
429 with retry_afterThe request hit a limitWait for the stated delay; respect global scope
401 or 403Authentication or permission problemFix 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.

Delay helper · application jobs
function retryDelayMs(attempt: number): number {
const ceiling = Math.min(30_000, 500 * 2 ** Math.min(attempt, 10));
return Math.floor(Math.random() * ceiling);
}

// Retry only temporary failures, with a maximum attempt count.
// For Discord 429 responses, follow retry_after instead.

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.

keep reading

More from the blog

All articles