You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Crawler / bot abuse — The public API is exposed to the internet. Facebook's crawler bots and similar have been observed hitting the API. Without throttling, a bot or misconfigured client can saturate the server.
Proposed Approach
Use DRF's built-in throttling framework (rest_framework.throttling).
2. Worker-specific throttle for job polling endpoints:
fromrest_framework.throttlingimportSimpleRateThrottleclassWorkerPollThrottle(SimpleRateThrottle):
scope="worker"defget_cache_key(self, request, view):
# Throttle by auth token or processing_service_nameifrequest.user.is_authenticated:
returnself.cache_format% {"scope": self.scope, "ident": request.user.pk}
returnNone
Apply to JobViewSet.list when ids_only=1 or incomplete_only=1 query params are present (these are the worker polling patterns).
3. Backend: Use Redis (already in the stack) for throttle state via django-redis cache backend.
Considerations
DRF returns 429 Too Many Requests with a Retry-After header — well-behaved clients (including ADC worker) should respect this
The ADC worker's get_jobs() already has a try/except around the HTTP call, so 429s would be handled gracefully (logged as error, retry on next poll cycle)
Consider whether ScopedRateThrottle is more appropriate for fine-grained per-view control
Burst vs sustained rates: DRF's default uses a simple sliding window; for more sophisticated token-bucket behavior, consider django-ratelimit or a reverse proxy (nginx/Caddy) layer
Context
Observed during PSv2 integration testing (2026-02-20)
Problem
Antenna has no API rate limiting. This creates two risks:
Worker polling storms — Multiple ADC workers polling
/jobs/every 5 seconds each. With N workers x M pipelines, this scales linearly. We recently consolidated to a singlepipeline__slug__incall per poll cycle (PSv2: Improve task fetching & web worker concurrency configuration #1142, feat: fetch jobs for all pipelines in a single API request ami-data-companion#114), but there's no server-side protection if workers misbehave or a bug causes tight retry loops.Crawler / bot abuse — The public API is exposed to the internet. Facebook's crawler bots and similar have been observed hitting the API. Without throttling, a bot or misconfigured client can saturate the server.
Proposed Approach
Use DRF's built-in throttling framework (
rest_framework.throttling).Throttle classes to configure
anonuserworkerImplementation sketch
1. Settings (
config/settings/base.py):2. Worker-specific throttle for job polling endpoints:
Apply to
JobViewSet.listwhenids_only=1orincomplete_only=1query params are present (these are the worker polling patterns).3. Backend: Use Redis (already in the stack) for throttle state via
django-rediscache backend.Considerations
429 Too Many Requestswith aRetry-Afterheader — well-behaved clients (including ADC worker) should respect thisget_jobs()already has a try/except around the HTTP call, so 429s would be handled gracefully (logged as error, retry on next poll cycle)ScopedRateThrottleis more appropriate for fine-grained per-view controldjango-ratelimitor a reverse proxy (nginx/Caddy) layerContext