Skip to content

feat(rate-limit): implement Token Bucket algorithm for rate-limiting middleware for search API protection#1669

Merged
leonagoel merged 1 commit into
leonagoel:mainfrom
koushik-gupta:feat/token-bucket-rate-limit-search
Jul 2, 2026
Merged

feat(rate-limit): implement Token Bucket algorithm for rate-limiting middleware for search API protection#1669
leonagoel merged 1 commit into
leonagoel:mainfrom
koushik-gupta:feat/token-bucket-rate-limit-search

Conversation

@koushik-gupta

Copy link
Copy Markdown

What changed

Implements a Token Bucket rate-limiting algorithm for the /api/search endpoint to protect it from scraper floods and rapid automation, as requested in Issue #887.

Core changes

  • backend/main.py: Upgraded _apply_rate_limit() from a sliding-window list to a true Token Bucket algorithm. Each (scope, client_ip) pair gets its own bucket with continuous token refill at rate_limit / 60 tokens/second. Requests are allowed when ≥ 1 token is available; excess requests receive a 429.
  • Also removed duplicate definitions of the rate-limit helpers that existed at two locations (prior merge conflict artifact).
  • Fixed missing _model_lock = Lock() global and orphaned return result in _clear_response_cache().
  • celery_app.py: Fixed IndentationError/NameError from upstream.
  • src/model/hybrid_model.py: Removed rogue merge-conflict block in select_bandit_arm.
  • tests/test_patches.py: Updated to use correct Token Bucket bucket format and full function signature.
  • .env.example: Documented all RATE_LIMIT_*_PER_MIN environment variables.

How Token Bucket works

capacity    = rate_limit               # max burst = full-minute quota
refill_rate = rate_limit / 60.0        # tokens per second
tokens      = min(capacity, tokens + elapsed * refill_rate)
if tokens >= 1.0:
    allow  (tokens -= 1)
else:
    return 429 Too Many Requests

Test results

  • test_search_rate_limit_returns_headers_before_limit
  • test_search_rate_limit_rejects_excess_requests
  • test_non_limited_endpoint_does_not_emit_rate_limit_headers
  • test_github_webhook_uses_rate_limit_scope
  • test_similar_rate_limit_rejects_excess_requests
  • test_rate_limiter_dos_mitigation_speed ✅ (< 2ms under 5,000 IP load)

Closes #887

@github-actions

Copy link
Copy Markdown

🎉 Welcome to Hybrid Recommender, @koushik-gupta! This is your first contribution here!

Labels added: gssoc:approved | mentor:leonagoel | status:review-needed

PR Description Checklist:

YES - What changed section
NO - Why section
NO - How to test section
YES - Related issue linked

⚠️ Some required sections are missing. Please update your PR description.

What happens next:

  1. @leonagoel will review your changes
  2. CI checks must pass
  3. Once approved, this PR will be auto-merged

⏱️ Please respond to review comments within 48 hours.

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1633 ("fix: Duplicate results-processing loop removed from search_items(#1631)") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1640 ("fix: resolve hybrid_model merge conflicts and add explanation string") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1641 ("Fix/svd memory leak") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1642 ("Feature/evaluation dashboard") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1643 ("Feature/streamlit tfidf config") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1644 ("Fix/strict csrf origin validation") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1645 ("Feature/svd online updating") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1647 ("fix: add title query param endpoint to resolve HTTP 422 (#1075)") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1648 ("fix(federated): prevent regularization decay in aggregate_updates") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1650 ("fix: remove duplicate code block in hybrid_model.py causing Indentati…") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1653 ("fix: remove duplicate /api/recommend route") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1654 ("build: add faiss dependency for two-tower retrieval") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1655 ("fix: enforce stronger signup password validation") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1660 ("security: reject unissued csrf tokens") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1661 ("feat: add KNN-based user collaborative filtering (Issue #51)") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1665 ("fix: add missing faiss-cpu dependency to requirements.txt ") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1515 ("feat: harden realtime recommendation WebSocket flow") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

@koushik-gupta
koushik-gupta force-pushed the feat/token-bucket-rate-limit-search branch from b482b5c to 379a1e6 Compare June 26, 2026 13:56
@github-actions

Copy link
Copy Markdown

⚠️ Main branch was just updated!

PR #1668 ("fix(ci): resolve syntax and indentation errors breaking upstream main") was just merged into main.

Please rebase your branch to avoid conflicts:

git fetch origin
git rebase origin/main
git push --force-with-lease

Keeping your branch up to date prevents merge conflicts. 🚀

…tection

Closes leonagoel#887

- Upgraded _apply_rate_limit() from a sliding-window (list of timestamps)
  to a true **Token Bucket** algorithm (tokens + last_updated dict per bucket).
  Each (scope, client_ip) pair gets its own bucket that refills continuously
  at 
ate_limit / 60 tokens per second.  A request is allowed instantly when
  >= 1 token is available; excess requests receive a standards-compliant 429.

- Removed the **duplicate** definitions of _get_rate_limit,
  _rate_limit_exceeded_response, and _apply_rate_limit that existed at two
  separate locations due to a prior merge conflict.

- Added missing _model_lock = Lock() global that was referenced but never
  defined, fixing a NameError in the recommendation endpoint.

- Removed orphaned 
eturn result statement from _clear_response_cache().

- Fixed celery_app.py indentation and NameError (�pp -> celery_app).

- Fixed src/model/hybrid_model.py rogue merge conflict block inside
  select_bandit_arm that caused an IndentationError.

- Updated 	ests/test_patches.py to use the correct Token Bucket bucket
  structure and full _apply_rate_limit() signature.

- Documented all rate-limiting env variables in .env.example.

`
capacity    = rate_limit               # max burst = full-minute quota
refill_rate = rate_limit / 60.0        # tokens per second
tokens      = min(capacity, tokens + elapsed * refill_rate)
if tokens >= 1: allow (tokens -= 1) else: 429
`

- test_search_rate_limit_returns_headers_before_limit  PASSED
- test_search_rate_limit_rejects_excess_requests       PASSED
- test_non_limited_endpoint_does_not_emit_rate_limit_headers PASSED
- test_github_webhook_uses_rate_limit_scope            PASSED
- test_similar_rate_limit_rejects_excess_requests      PASSED
- test_rate_limiter_dos_mitigation_speed               PASSED (< 2ms under 5k IPs)
@koushik-gupta
koushik-gupta force-pushed the feat/token-bucket-rate-limit-search branch from 379a1e6 to 3a452af Compare July 2, 2026 02:57
This was referenced Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Integrate Token Bucket rate-limiting middleware for search API protection

2 participants