Merged
Conversation
The previous implementation used golang.org/x/time/rate which implements a token bucket algorithm that continuously refills tokens. This caused 429 errors because: 1. Token bucket allows exceeding fixed-window limits through gradual refills Example: With 5/min limit, burst of 5 + gradual refills = ~10 req/min in sliding windows, exceeding 3commas' strict 5/min fixed-window limit 2. 429 handler only blocked the matched route, not the tier limiter When tier limit was exceeded, only specific routes were blocked, allowing 429s to cascade across other endpoints Changes: - Implemented custom fixedWindowLimiter that aligns to clock boundaries - Windows reset at fixed times (e.g., 12:30:00, 12:31:00) matching 3commas API - Allows bursts within same window (e.g., 5 requests in 2 seconds is fine) - Renamed "global" to "tier" for clarity (represents subscription plan limit) - Fixed 429 handler to always block tier limiter, not just routes - Removed golang.org/x/time/rate dependency This matches 3commas' actual rate limiting behavior where limits reset at the start of each time window, rather than continuous token refills.
Updated rate limiting documentation to reflect the new implementation: - Changed from "token bucket algorithm" to "fixed-window rate limiting" - Added explanation of clock-aligned windows - Clarified that bursts within same window are allowed - Better explains actual behavior matching 3Commas API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixed rate limiter implementation to prevent 429 errors by replacing token bucket algorithm with fixed-window rate limiting that matches 3commas API behavior.
Problem
The SDK was getting frequent 429 (Too Many Requests) errors despite having client-side rate limiting. Two issues were identified:
Token bucket vs Fixed-window mismatch: The previous implementation used
golang.org/x/time/rate(token bucket algorithm) which continuously refills tokens. This doesn't match 3commas API's fixed-window rate limiting that resets at clock boundaries (e.g., 12:30:00, 12:31:00).With token bucket and PlanStarter (5/min), you could make 5 requests immediately, then earn additional tokens through gradual refills, resulting in ~10 requests within various 60-second sliding windows - exceeding the API's strict 5/minute limit.
429 handler only blocked routes, not tier limiter: When a 429 was received and matched a specific route, only that route was blocked. The tier limiter (account-wide subscription limit) wasn't blocked, causing cascading 429 errors across other endpoints.
Solution
fixedWindowLimiterthat aligns to clock boundaries usingtime.Truncate()golang.org/x/time/ratedependencyTesting
All existing tests pass. Rate limiting tests confirm proper enforcement of tier limits with window-aligned behavior.