Limit_req_zone to sleep instead of an error 504 or 404

I would like to propose to replace the error code “limit_req_zone” sends
to a user with a simple sleep statement instead.

I am using limit_req_zone on some production servers to limit the amount
downloads each ip can execute over time. “fastcgi_param” is used to
an external fastcgi script to deliver the data to the client from a
back end cluster.

Users are accessing the nginx front end using automated scripts and
data without problem as long as they stay below our limit_req_zone value
of 200
requests per 60 seconds.

When they hit the limit_req_zone value the clients are being limited
and being delayed until their requests per minute goes below the
specified value.

My issue is when a user hits the limit an error 503 (for local files) or
error 404 (for fastcgi scripts) is sent back to the user. The error
503 is documented
on the nginx site and expected as “service unavailable”. The error 404
for fastcgi is
not mentioned and took some trial and error to figure out why it was
in the logs.

For those interested, here is a sanitized copy of the error.log. The
client does a
head request and has exceeded 200 req/min by 0.094 req/min. At this
point I would
imagine a 503 would be sent back to the client. Instead, the second
error line
shows nginx trying to look for the URI on the local file system. The
problem is
file.bz2 is the file the fastcgi script would serve out and is not a
local file in
htdocs. The script is really located at /disk/web/cgi/getter .

Here is the nginx.conf for getting a file through the fast cgi method:

limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;

root /disk/web/htdocs;
limit_req zone=one burst=100 nodelay;

 location ~* ^/script/[\w.-]+$ {
         gzip off;
         fastcgi_max_temp_file_size 0;
         fastcgi_split_path_info ^((?U).+script)(/?.+)$;
         fastcgi_intercept_errors on; #<--------
         fastcgi_pass unix:/var/run/fcgiwrap.socket;
         include /usr/local/nginx/conf/fastcgi_params;
         fastcgi_param DOCUMENT_ROOT $document_root;
         fastcgi_param PATH_INFO $fastcgi_path_info;
         fastcgi_param SCRIPT_NAME /cgi/getter;
         fastcgi_param SCRIPT_FILENAME /disk/web/cgi/getter;

2012/06/21 15:04:43 [error] 19685#0: *11354 limiting requests, excess:
200.094 by zone “one”, client: 128.x.x.x, server: ourserver, request:
“HEAD /cgi/getter/file.bz2 HTTP/1.1”, host: “ourserver”

2012/06/21 15:04:53 [error] 19685#0: *11354 open()
“/disk/web/htdocs/cgi/getter/file.bz2” failed (2: No such file or
directory), client: 128.x.x.x, server: ourserver, request: “HEAD
/cgi/getter/file.bz2 HTTP/1.1”, host: “ourserver”

Sending back an error 404 (File not found) for a file that does exist
an external script causes a lot of confusion to the user. This is may be
a unforeseen coding issue though.

I propose a better situation is to limit users, but when they hit the
limit_req_zone value have the options to sleep for a few seconds, check
they are under the request limit and then complete the original request.
simple delay in responding to the client, similar to Maxim’s
would be invaluable.

Perhaps adding an option to the limit_req_zone directive would be good.

limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;
(or if you want to send an error)
limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;

Another idea is for limit_req_zone to trigger an unused error code
(12345) and
allow the nginx config to trap it. This way the admin could delay the
or even send back an error.

error_page 12345 @abuse
location /abuse {
delay 5s;

I am going to look in the nginx source for where nginx is sending the
504 for
limit_req_zone from. If anyone has any other ideas I would be happy to
them and very open to suggestions.

Please disregard my previous email.

The issue was on my side when I setup error_page with a delay, but
then forgot to setup the proper error response.