Skip to content

implement API rate limiter and throttling#17

Merged
dnjstr merged 6 commits into
mainfrom
development
May 5, 2026
Merged

implement API rate limiter and throttling#17
dnjstr merged 6 commits into
mainfrom
development

Conversation

@6reenhorn
Copy link
Copy Markdown
Owner

This PR introduces a robust rate-limiting (throttling) layer to the QueueLess API to protect against spam, brute-force joins, and aggressive polling. By implementing this, we ensure system stability even during high-traffic spikes and prevent individual users from monopolizing server resources.

Key Changes

  • Multi-Layer Throttling

    • Join Queue Protection: Added a strict limit of 5 requests per minute for the /api/queue/join/ endpoint.
    • Burst/Polling Protection: Added a generous 30 requests per minute limit for status checks, check-ins, and cancellations to accommodate active browser sessions while blocking excessive automation.
    • Daily Quotas: Set base anonymous limits to 100/day and authenticated limits to 1000/day.
  • Architectural Cleanliness

    • Introduced queue_tracker/throttles.py to house custom throttle classes (JoinQueueRateThrottle, BurstRateThrottle).
    • Decoupled throttle rates into settings.py for easy environment-specific adjustments.
  • Load Balancer Ready

    • The throttling state is managed via the Redis cache, ensuring that rate limits are enforced consistently even when the application is scaled horizontally across multiple instances.

Testing Done

  • Verified that existing QueueJoinViewTests and other tracking tests pass.
  • Manually verified that exceeding the 5-join-per-minute limit correctly returns a 429 Too Many Requests status code.
  • Confirmed that legitimate polling within the 30/min window remains uninterrupted.

Test Results:

Ran 3 tests in 0.210s
OK

How to Test

  1. Try to join a queue more than 5 times within one minute from the same IP.
  2. You should receive a 429 Too Many Requests response with a message indicating when you can try again.
  3. Verify that normal status polling (once every few seconds) still works without being blocked.

Copilot AI review requested due to automatic review settings May 5, 2026 14:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Django REST Framework throttling to protect key QueueLess API endpoints (queue join + polling-style endpoints) and introduces custom throttle scopes intended to cap burst traffic and joins.

Changes:

  • Added global DRF throttling configuration (daily anon/user quotas + scoped rates) in settings.py.
  • Introduced JoinQueueRateThrottle / BurstRateThrottle and applied them to queue join/status/check-in/cancel endpoints.
  • Added a scratch throttling “test” script.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
scratch/test_throttling.py Adds a script-like throttling check, currently named/structured like a pytest test.
queueless_backend/queueless_backend/settings.py Configures DRF default throttles/rates (daily quotas + join/burst rates).
queueless_backend/queue_tracker/views.py Applies join/burst throttles to public queue endpoints.
queueless_backend/queue_tracker/throttles.py Defines two throttle classes with join and burst scopes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scratch/test_throttling.py Outdated
Comment thread scratch/test_throttling.py Outdated
Comment thread queueless_backend/queue_tracker/views.py
Comment thread queueless_backend/queue_tracker/views.py
Comment thread queueless_backend/queue_tracker/throttles.py Outdated
Comment thread queueless_backend/queueless_backend/settings.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread queueless_backend/queue_tracker/views.py
Comment thread queueless_backend/queue_tracker/throttles.py Outdated
Comment thread queueless_backend/queueless_backend/settings.py Outdated
Comment thread queueless_backend/queueless_backend/settings.py
Comment thread queueless_backend/queue_tracker/views.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread queueless_backend/queueless_backend/settings.py
Comment thread queueless_backend/queueless_backend/settings.py Outdated
Comment thread queueless_backend/queueless_backend/settings.py Outdated
Comment thread queueless_backend/queue_tracker/throttles.py Outdated
Comment thread queueless_backend/queue_tracker/tests.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread queueless_backend/queueless_backend/settings.py
Comment thread queueless_backend/queueless_backend/settings.py
Comment thread queueless_backend/queueless_backend/settings.py
Comment thread queueless_backend/queue_tracker/tests.py
Comment thread queueless_backend/queue_tracker/tests.py Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +196 to +201
"DEFAULT_THROTTLE_RATES": {
"anon": os.getenv("DRF_THROTTLE_RATE_ANON", "20000/day"),
"user": os.getenv("DRF_THROTTLE_RATE_USER", "100000/day"),
"burst": os.getenv("DRF_THROTTLE_RATE_BURST", "60/minute"),
"join": os.getenv("DRF_THROTTLE_RATE_JOIN", "5/minute"),
},
Comment on lines +190 to +195
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
"rest_framework.throttling.ScopedRateThrottle",
],
Comment on lines 165 to 169
class QueueEntryCheckInView(APIView):
permission_classes = [permissions.AllowAny]
throttle_scope = "burst"

def patch(self, request, session_id):
Comment on lines 186 to 190
class QueueEntryCancelView(APIView):
permission_classes = [permissions.AllowAny]
throttle_scope = "burst"

def post(self, request, session_id):
@dnjstr dnjstr merged commit 2006954 into main May 5, 2026
6 checks 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.

3 participants