diff --git a/pkg/sources/github/github.go b/pkg/sources/github/github.go index 0cfd3af305eb..0a2ea2eed87e 100644 --- a/pkg/sources/github/github.go +++ b/pkg/sources/github/github.go @@ -829,16 +829,22 @@ func (s *Source) scan(ctx context.Context, installationClient *github.Client, ch // This will likely only be exhausted if many users/orgs are scanned without auth func (s *Source) handleRateLimit(errIn error, res *github.Response) bool { var ( + now = time.Now() knownWait = true remaining = 0 retryAfter time.Duration ) // GitHub has both primary (RateLimit) and secondary (AbuseRateLimit) errors. - var rateLimit *github.RateLimitError - var abuseLimit *github.AbuseRateLimitError + var ( + rateLimit *github.RateLimitError + abuseLimit *github.AbuseRateLimitError + ) if errors.As(errIn, &rateLimit) { - // Do nothing + rate := rateLimit.Rate + if rate.Remaining == 0 { + retryAfter = rate.Reset.Sub(now) + } } else if errors.As(errIn, &abuseLimit) { retryAfter = abuseLimit.GetRetryAfter() } else { @@ -850,25 +856,33 @@ func (s *Source) handleRateLimit(errIn error, res *github.Response) bool { // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#exceeding-the-rate-limit if retryAfter <= 0 && res != nil { var err error - remaining, err = strconv.Atoi(res.Header.Get("x-ratelimit-remaining")) - if err != nil { - knownWait = false + + remainingHeader := res.Header.Get("x-ratelimit-remaining") + if remainingHeader != "" { + if remaining, err = strconv.Atoi(remainingHeader); err != nil { + knownWait = false + } } - resetTime, err := strconv.Atoi(res.Header.Get("x-ratelimit-reset")) - if err != nil || resetTime == 0 { - knownWait = false - } else if resetTime > 0 { - retryAfter = time.Duration(int64(resetTime)-time.Now().Unix()) * time.Second + resetHeader := res.Header.Get("x-ratelimit-reset") + if resetHeader != "" { + resetTime, err := strconv.Atoi(resetHeader) + if err != nil || resetTime == 0 { + knownWait = false + } else if resetTime > 0 { + retryAfter = time.Duration(int64(resetTime)-now.Unix()) * time.Second + } } } - resumeTime := time.Now().Add(retryAfter).String() + var resumeTime string if knownWait && remaining == 0 && retryAfter > 0 { + resumeTime = now.Add(retryAfter).String() s.log.V(2).Info("rate limited", "retry_after", retryAfter.String(), "resume_time", resumeTime) } else { - // TODO: Use exponential backoff instead of static retry time. retryAfter = time.Minute * 5 + resumeTime = now.Add(retryAfter).String() + // TODO: Use exponential backoff instead of static retry time. s.log.V(2).Error(errIn, "unexpected rate limit error", "retry_after", retryAfter.String(), "resume_time", resumeTime) } time.Sleep(retryAfter)