Skip to content

fix: make rate limiter atomic#197

Open
GhanshyamJha05 wants to merge 1 commit into
Coder-s-OG-s:mainfrom
GhanshyamJha05:fix/issue-134-atomic-rate-limit
Open

fix: make rate limiter atomic#197
GhanshyamJha05 wants to merge 1 commit into
Coder-s-OG-s:mainfrom
GhanshyamJha05:fix/issue-134-atomic-rate-limit

Conversation

@GhanshyamJha05
Copy link
Copy Markdown

Summary

Fixes a concurrency bug in the fixed-window rate limiter where parallel requests could bypass the limit because the counter update used a non-atomic cacheGet -> compare -> cacheSet flow.

This PR moves the rate-limit counter update into an atomic cache backend operation so concurrent requests for the same key cannot all read the same stale counter.

Type of Change

  • Bug fix

Related Issue

Closes #134

What was changed?

  • Replaced the non-atomic rateLimit() read/check/write flow with cacheRateLimitHit().
  • Added atomic rate-limit handling to the memory, Upstash Redis, and ioredis cache backends.
  • Used a Redis Lua script so production Redis updates happen as a single atomic operation.
  • Kept the existing rateLimit() API and response shape unchanged.
  • Added a concurrency regression test using Promise.all(...) to verify that only the configured limit is allowed during a burst.

Screenshots

Not applicable. This is a backend/security fix with no UI changes.

Checklist

  • My code follows the project structure and conventions
  • I tested this locally (npm run dev)
  • No hardcoded secrets or credentials
  • I have updated documentation if needed

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 21, 2026

@GhanshyamJha05 is attempting to deploy a commit to the codersogs-3057's projects Team on Vercel.

A member of the Team first needs to authorize it.

@GhanshyamJha05
Copy link
Copy Markdown
Author

Hi @Ayush-Patel-56 , I’ve opened this PR for #134.

I fixed the non-atomic rate limiter flow by moving the counter update into an atomic cache backend operation while keeping the existing rateLimit() API unchanged. I also added a concurrent burst regression test to make sure only the configured limit is allowed under Promise.all(...).

Verified locally with typecheck, lint, prettier check, and the full test suite. All 44 test files / 380 tests passed.

Copy link
Copy Markdown
Collaborator

@Siddhartha-singh01 Siddhartha-singh01 left a comment

Choose a reason for hiding this comment

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

@GhanshyamJha05 Just check the code base I think there is some noise in the code

@GhanshyamJha05 GhanshyamJha05 force-pushed the fix/issue-134-atomic-rate-limit branch from 2ddf824 to 8a4f020 Compare May 23, 2026 21:48
@GhanshyamJha05
Copy link
Copy Markdown
Author

Thanks for pointing that out. I checked the codebase again and reduced the noisy part of the implementation.

The earlier version added a larger Lua-script based path in cache.ts. I’ve simplified it to use Redis INCR with TTL, which still keeps the rate-limit increment atomic for concurrent requests but fits the existing cache abstraction more cleanly.

I also rebased the branch on latest main and reran the checks:

  • npm.cmd run typecheck
  • focused lint
  • full npm.cmd test

All 45 test files / 381 tests passed.

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.

Rate limiter is bypassable under concurrent requests (non-atomic counter)

2 participants