Created
November 24, 2024 21:05
-
-
Save ayourtch/abf5c9255634e3a347049c57a46a8831 to your computer and use it in GitHub Desktop.
Experiment rate limit in nginx suggested by Claude AI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Define a shared memory zone to store rate limit state | |
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s; | |
# Define a map to store the last failed attempt timestamp | |
map $remote_addr $last_failed_time { | |
volatile; | |
default 0; | |
} | |
# Define a map to store the retry count | |
map $remote_addr $retry_count { | |
volatile; | |
default 0; | |
} | |
# Calculate delay based on retry count (2^retry_count - 1) | |
map $retry_count $delay { | |
default 0; | |
"0" 0; | |
"1" 1; | |
"2" 3; | |
"3" 7; | |
"4" 15; | |
"5" 31; | |
} | |
server { | |
listen 80; | |
server_name example.com; | |
location / { | |
# Check if we need to delay based on previous 429 | |
if ($last_failed_time) { | |
set $wait_time 0; | |
# If Retry-After header was present in last response | |
if ($http_retry_after) { | |
set $wait_time $http_retry_after; | |
} | |
# Else use exponential backoff | |
if ($wait_time = 0) { | |
set $wait_time $delay; | |
} | |
# Calculate if enough time has passed | |
set $current_time $time_iso8601; | |
if ($current_time - $last_failed_time < $wait_time) { | |
return 429 'Too Many Requests\n'; | |
} | |
} | |
# Apply rate limiting | |
limit_req zone=req_limit_per_ip burst=5 nodelay; | |
# Track failed attempts | |
proxy_set_header X-Real-IP $remote_addr; | |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
proxy_set_header Host $http_host; | |
# If request is rate limited (429) | |
error_page 429 = @handle_429; | |
# Proxy to backend | |
proxy_pass http://backend; | |
} | |
location @handle_429 { | |
# Increment retry count | |
set $retry_count_new $retry_count; | |
if ($retry_count_new != "") { | |
set $retry_count_new $retry_count; | |
add_header X-Retry-Count $retry_count_new; | |
} | |
# Store timestamp of this failure | |
set $last_failed_time $time_iso8601; | |
# Return 429 with appropriate headers | |
add_header Retry-After $delay; | |
return 429 'Too Many Requests\n'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment