Skip to content

Commit 926124d

Browse files
authored
fix: account for burst in rate limit (#183)
* fix: account for burst in rate limit * chore: add comment for rate limit strategy consideration
1 parent 97dfd8b commit 926124d

File tree

1 file changed

+37
-4
lines changed

1 file changed

+37
-4
lines changed

internal/sdkclient/sdkclient.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,45 @@ type HookdeckRateLimiter struct {
7575
}
7676

7777
// NewHookdeckRateLimiter creates a rate limiter for Hookdeck's API limits.
78+
//
79+
// Rate Limiting Strategy:
80+
// - Initial burst: 5 requests (allows immediate execution for small operations)
81+
// - Steady rate: 230 requests/minute (3.83 req/sec)
82+
// - This results in max 235 requests in the first minute, then 230/min thereafter
83+
// - Conservative approach ensures we stay under the 240 req/min API limit
84+
//
85+
// API Rate Limit Headers:
86+
// The Hookdeck API returns the following rate limit headers in responses:
87+
// - Retry-After: Seconds before next request can be made
88+
// - X-RateLimit-Limit: Requests per minute limit for the API key
89+
// - X-RateLimit-Remaining: Remaining requests for the rate limit period
90+
// - X-RateLimit-Reset: ISO timestamp of the next rate limit period reset
91+
// Currently, we use client-side rate limiting and don't dynamically adjust based
92+
// on these headers, but they're available for debugging and future enhancements.
93+
//
94+
// Retry Considerations:
95+
// - We intentionally DO NOT implement automatic retries on 429 errors
96+
// - Retries would consume additional tokens from our rate limit bucket,
97+
// potentially causing cascading failures for subsequent requests
98+
// - If retry logic is needed, implement using recursion with retry count tracking,
99+
// ensuring each retry attempt goes through the rate limiter to maintain
100+
// the global rate limit invariant
101+
//
102+
// Performance Trade-offs:
103+
// - This rate limiter works well for large Terraform states (200+ resources)
104+
// - However, it significantly impacts small deployments:
105+
// - 100 resources now take ~30 seconds vs ~5 seconds previously
106+
// - This is an intentional trade-off for reliability and compliance
107+
// - Future optimization could implement a true "240 requests per sliding minute"
108+
// window instead of the current token bucket approach
109+
// - Potential solution: In-memory FIFO queue that tracks the last minute's
110+
// requests and blocks when 240 requests have been made in the past 60 seconds
78111
func NewHookdeckRateLimiter() *HookdeckRateLimiter {
79-
// 240 requests per minute = 4 per second
80-
// Use rate.Every for cleaner per-minute expression
81-
// Burst of 10 allows for short bursts of activity
112+
// API limit: 240 requests per minute
113+
// We use 230 req/min with burst of 5 to stay safely under the limit
114+
// 230 + 5 = 235 total possible requests in first minute (5 request buffer)
82115
return &HookdeckRateLimiter{
83-
limiter: rate.NewLimiter(rate.Every(time.Minute/240), 10),
116+
limiter: rate.NewLimiter(rate.Every(time.Minute/230), 5),
84117
}
85118
}
86119

0 commit comments

Comments
 (0)