Skip to content

feat(api): add rate limiter#2157

Merged
jakubno merged 10 commits into
mainfrom
feat/add-rate-limiter
Mar 18, 2026
Merged

feat(api): add rate limiter#2157
jakubno merged 10 commits into
mainfrom
feat/add-rate-limiter

Conversation

@jakubno
Copy link
Copy Markdown
Member

@jakubno jakubno commented Mar 18, 2026

Note

Medium Risk
Adds a Redis-backed rate limiting middleware into the API request path, which can return new 429/500 responses when enabled and depends on Redis availability and correct LaunchDarkly flag configuration.

Overview
This PR introduces a per-team, Redis-backed rate limiter for API requests (using go-redis/redis_rate) and wires it into the Gin server behind a new LaunchDarkly kill-switch flag, with optional per-route rate/burst overrides driven by a JSON flag; it also refactors startup so Redis and the feature-flag client are initialized in main and injected into APIStore/server construction, and adds unit/integration tests covering fail-open/closed behavior, headers, burst/refill, and concurrency.

Written by Cursor Bugbot for commit 0fcd39c. This will update automatically on new commits. Configure here.

Comment thread packages/api/internal/middleware/ratelimit/ratelimit.go Outdated
Comment thread packages/api/internal/middleware/ratelimit/ratelimit.go Outdated
Comment thread packages/api/main.go
Comment thread packages/api/main.go
Comment thread packages/api/main.go Outdated
@jakubno jakubno changed the title feat(api): add rate limiter for some endpoints feat(api): add rate limiter Mar 18, 2026
Comment thread packages/api/main.go
}
cleanupFns = append(cleanupFns, func(_ context.Context) error {
return redisClient.Close()
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redis client closed concurrently with dependent cache cleanup

Low Severity

Moving Redis client creation out of APIStore and adding its Close as a separate entry in cleanupFns introduces a race condition during shutdown. All cleanup functions run in parallel goroutines, so redisClient.Close() can complete while apiStore.Close() is still executing Redis-dependent operations like snapshotCache.Close(), templateCache.Close(), and templateBuildsCache.Close(). Previously, the Redis client was closed at the end of apiStore.Close(), ensuring sequential ordering. Now these run concurrently, causing spurious errors during shutdown.

Additional Locations (2)
Fix in Cursor Fix in Web

Comment thread packages/api/main.go Outdated
Comment thread packages/shared/pkg/featureflags/flags.go
Comment thread packages/api/internal/middleware/ratelimit/ratelimit.go Outdated

logger.L().Warn(ctx, "rate limit exceeded",
logger.WithTeamID(teamID),
zap.Int("retry_after_s", retryAfterSecs),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets add also the rate limit fields, ideally set them on the logger early and reuse the instance

Comment thread packages/api/internal/middleware/ratelimit/ratelimit.go
@jakubno jakubno requested a review from dobrac March 18, 2026 13:55
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread packages/api/internal/middleware/ratelimit/ratelimit_test.go Outdated
@jakubno jakubno merged commit b270ce9 into main Mar 18, 2026
36 checks passed
@jakubno jakubno deleted the feat/add-rate-limiter branch March 18, 2026 14:39
ValentaTomas pushed a commit that referenced this pull request May 4, 2026
* feat(api): add rate limiter for some endpoints

* chore: make tidy

* Update packages/api/internal/middleware/ratelimit/ratelimit.go

* Apply suggestion from @jakubno

* chore: generalize the rate limiter

* fix: close redis and feature flags client correctly

* fix: test

* fix: lint

* chore: pr comments

* fix: test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants