Skip to content

Commit

Permalink
Add option to disable rate-limited request retry (#1151)
Browse files Browse the repository at this point in the history
* Add option to disable rate-limited request retry

Closes #1011.

* feat: code review changes

Co-authored-by: nitroflap <fe.lap.prog@gmail.com>
  • Loading branch information
njhanley and FedorLap2006 committed Apr 14, 2022
1 parent 2b35977 commit c615fc7
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
1 change: 1 addition & 0 deletions discord.go
Expand Up @@ -36,6 +36,7 @@ func New(token string) (s *Session, err error) {
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShouldRetryOnRateLimit: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
Expand Down
29 changes: 23 additions & 6 deletions restapi.go
Expand Up @@ -73,6 +73,18 @@ func (r RESTError) Error() string {
return "HTTP " + r.Response.Status + ", " + string(r.ResponseBody)
}

// RateLimitError is returned when a request exceeds a rate limit
// and ShouldRetryOnRateLimit is false. The request may be manually
// retried after waiting the duration specified by RetryAfter.
type RateLimitError struct {
*RateLimit
}

// Error returns a rate limit error with rate limited endpoint and retry time.
func (e RateLimitError) Error() string {
return "Rate limit exceeded on " + e.URL + ", retry after " + e.RetryAfter.String()
}

// Request is the same as RequestWithBucketID but the bucket id is the same as the urlStr
func (s *Session) Request(method, urlStr string, data interface{}) (response []byte, err error) {
return s.RequestWithBucketID(method, urlStr, data, strings.SplitN(urlStr, "?", 2)[0])
Expand Down Expand Up @@ -186,14 +198,19 @@ func (s *Session) RequestWithLockedBucket(method, urlStr, contentType string, b
s.log(LogError, "rate limit unmarshal error, %s", err)
return
}
s.log(LogInformational, "Rate Limiting %s, retry in %v", urlStr, rl.RetryAfter)
s.handleEvent(rateLimitEventType, &RateLimit{TooManyRequests: &rl, URL: urlStr})

time.Sleep(rl.RetryAfter)
// we can make the above smarter
// this method can cause longer delays than required
if s.ShouldRetryOnRateLimit {
s.log(LogInformational, "Rate Limiting %s, retry in %v", urlStr, rl.RetryAfter)
s.handleEvent(rateLimitEventType, &RateLimit{TooManyRequests: &rl, URL: urlStr})

response, err = s.RequestWithLockedBucket(method, urlStr, contentType, b, s.Ratelimiter.LockBucketObject(bucket), sequence)
time.Sleep(rl.RetryAfter)
// we can make the above smarter
// this method can cause longer delays than required

response, err = s.RequestWithLockedBucket(method, urlStr, contentType, b, s.Ratelimiter.LockBucketObject(bucket), sequence)
} else {
err = &RateLimitError{&RateLimit{TooManyRequests: &rl, URL: urlStr}}
}
case http.StatusUnauthorized:
if strings.Index(s.Token, "Bot ") != 0 {
s.log(LogInformational, ErrUnauthorized.Error())
Expand Down
3 changes: 3 additions & 0 deletions structs.go
Expand Up @@ -43,6 +43,9 @@ type Session struct {
// Should the session reconnect the websocket on errors.
ShouldReconnectOnError bool

// Should the session retry requests when rate limited.
ShouldRetryOnRateLimit bool

// Identify is sent during initial handshake with the discord gateway.
// https://discord.com/developers/docs/topics/gateway#identify
Identify Identify
Expand Down

0 comments on commit c615fc7

Please sign in to comment.