Skip to content

Commit 1c82254

Browse files
committed
rename existing rateLimiter to requestThrottler and reduce throughput limits to match github secondary rate limits
Signed-off-by: Eric Pickard <piceri@github.com>
1 parent 95f9605 commit 1c82254

File tree

2 files changed

+23
-21
lines changed

2 files changed

+23
-21
lines changed

pkg/deploymentrecord/client.go

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ var validOrgPattern = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
3131

3232
// Client is an API client for posting deployment records.
3333
type Client struct {
34-
baseURL string
35-
org string
36-
httpClient *http.Client
37-
retries int
38-
apiToken string
39-
transport *ghinstallation.Transport
40-
rateLimiter *rate.Limiter
34+
baseURL string
35+
org string
36+
httpClient *http.Client
37+
retries int
38+
apiToken string
39+
transport *ghinstallation.Transport
40+
requestThrottler *rate.Limiter
4141

4242
// rateLimitDelay is shared across workers
4343
rateLimitDelayMu sync.Mutex
@@ -75,8 +75,8 @@ func NewClient(baseURL, org string, opts ...ClientOption) (*Client, error) {
7575
Timeout: 5 * time.Second,
7676
},
7777
retries: 3,
78-
// 20 req/sec with burst of 50
79-
rateLimiter: rate.NewLimiter(rate.Limit(20), 50),
78+
// 3 req/sec (180 req/min) with burst of 20
79+
requestThrottler: rate.NewLimiter(rate.Limit(3), 20),
8080
}
8181

8282
for _, opt := range opts {
@@ -145,10 +145,10 @@ func WithGHApp(id, installID string, pkBytes []byte, pkPath string) ClientOption
145145
}
146146
}
147147

148-
// WithRateLimiter sets a custom rate limiter for API calls.
149-
func WithRateLimiter(rps float64, burst int) ClientOption {
148+
// WithRequestThrottler sets a custom rate limiter for API calls.
149+
func WithRequestThrottler(rps float64, burst int) ClientOption {
150150
return func(c *Client) {
151-
c.rateLimiter = rate.NewLimiter(rate.Limit(rps), burst)
151+
c.requestThrottler = rate.NewLimiter(rate.Limit(rps), burst)
152152
}
153153
}
154154

@@ -185,9 +185,9 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error {
185185
return errors.New("record cannot be nil")
186186
}
187187

188-
// Wait for rate limiter
189-
if err := c.rateLimiter.Wait(ctx); err != nil {
190-
return fmt.Errorf("rate limiter wait failed: %w", err)
188+
// Wait for request throttler
189+
if err := c.requestThrottler.Wait(ctx); err != nil {
190+
return fmt.Errorf("request throttler wait failed: %w", err)
191191
}
192192

193193
url := fmt.Sprintf("%s/orgs/%s/artifacts/metadata/deployment-record", c.baseURL, c.org)
@@ -206,7 +206,7 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error {
206206
return err
207207
}
208208

209-
if err = c.waitForSecondaryRateLimit(ctx); err != nil {
209+
if err = c.waitForServerRateLimit(ctx); err != nil {
210210
return err
211211
}
212212

@@ -320,9 +320,9 @@ func (c *Client) PostOne(ctx context.Context, record *DeploymentRecord) error {
320320
return fmt.Errorf("all retries exhausted: %w", lastErr)
321321
}
322322

323-
// waitForSecondaryRateLimit blocks until the global secondary rate limit backoff has elapsed.
323+
// waitForServerRateLimit blocks until the global secondary rate limit backoff has elapsed.
324324
// All workers sharing this client observe the same deadline.
325-
func (c *Client) waitForSecondaryRateLimit(ctx context.Context) error {
325+
func (c *Client) waitForServerRateLimit(ctx context.Context) error {
326326
c.rateLimitDelayMu.Lock()
327327
waitUntil := c.rateLimitDelay
328328
c.rateLimitDelayMu.Unlock()
@@ -332,15 +332,15 @@ func (c *Client) waitForSecondaryRateLimit(ctx context.Context) error {
332332
return nil
333333
}
334334

335-
slog.Info("waiting for secondary rate limit backoff",
335+
slog.Info("waiting for server rate limit backoff",
336336
"delay", delay.Round(time.Millisecond),
337337
)
338338

339339
select {
340340
case <-time.After(delay):
341341
return nil
342342
case <-ctx.Done():
343-
return fmt.Errorf("context cancelled during secondary rate limit wait: %w", ctx.Err())
343+
return fmt.Errorf("context cancelled during server rate limit wait: %w", ctx.Err())
344344
}
345345
}
346346

@@ -363,6 +363,8 @@ func parseRateLimitDelay(resp *http.Response) time.Duration {
363363
var retryAfterDelay *time.Duration
364364
if ra := resp.Header.Get("Retry-After"); ra != "" {
365365
if seconds, err := strconv.Atoi(ra); err == nil {
366+
// Max Retry-After of 60 seconds
367+
seconds = min(seconds, 60)
366368
rad := time.Duration(seconds) * time.Second
367369
retryAfterDelay = &rad
368370
}

pkg/deploymentrecord/client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ func TestPostOneRespectsRetryAfterAcrossGoroutines(t *testing.T) {
717717
wg.Wait()
718718

719719
elapsed := time.Since(start)
720-
if elapsed < 1800*time.Millisecond {
720+
if elapsed < 1500*time.Millisecond {
721721
t.Errorf("goroutine 2 should have waited for retry-after, but only waited %v", elapsed)
722722
}
723723
}

0 commit comments

Comments
 (0)