post_action, just send http request, not fcgi - more questions + post_action bug?

Rob Mueller robm at
Fri Mar 7 06:17:37 MSK 2008

> I thought something hacky like this might work.
>    location = @done {
>      set    $rateuser     $upstream_http_x_rate_user;
>      proxy_set_header RateUser $rateuser;
>      proxy_set_header RateURI  $request_uri;
>      proxy_set_header RateBytes $body_bytes_sent;
>      proxy_pass;
>    }
> And indeed for GET requests it does nicely, I get the headers I want which 
> I can quickly and easily decode them. In fact I don't really need to set 
> RateURI, since the first first line of the request gives me the URI.
> If I do a POST though, nginx isn't happy.

Playing around some more, I found I could do this:

    location = @done {
      set    $rateuser     $upstream_http_x_rate_user;
      proxy_set_header RateUser $rateuser;
      proxy_set_header RateURI  $request_uri;
      proxy_set_header RateBytes $body_bytes_sent;
      proxy_pass_request_body off;
      proxy_pass_request_headers off;
      proxy_pass http://unix:/var/state/ratetrack/ratepostaction:/;

Adding the "proxy_pass_request_body off" makes everything work nicely, and I 
added the "proxy_pass_request_headers off" because I don't really need that 
information, so might as well not send it. So this all seems to work nicely.

So is this the best/right way of doing this? I mean it currently seems to 
work, and to do what I want. However I realise that I'm abusing the "proxy" 
system for something it wasn't designed to do, so I don't know if this will 
break with future or if there is a better way of doing this?

Also what actually happens to the content that proxy_pass returns in this 
case. I really want it to just "disappear", and for the moment it does seem 
to do that, but is that guaranteed?

However on top of that, I'm also worried about something else as well. I did 
some testing where I setup the following situation.

1. Only 1 nginx worker process
2. Many backend post_action "http done handler" processes
3. The "http done handler" would sleep 30 seconds before returning the HTTP 

I wanted to test the case if the "http done handler" code I wrote got slow 
for some reason, that it didn't affect all of nginx.

What I found was that when I did the first request it worked, but if I did a 
second request in < 30 seconds, it would block (browser just spinning) for 
the 30 seconds to expire. It seems anything that occurs in the post_action 
handler blocks any new connections from being processed. And as mentioned, 
it's not because there weren't any other free "http done handler" processes.

I repeated the process, and straced nginx to see what was happening.

### about to do a request

epoll_wait(11, {{EPOLLIN, {u32=3081252872, u64=3081252872}}}, 512, -1) = 1
gettimeofday({1204859394, 326281}, NULL) = 0
accept(5, {sa_family=AF_INET, sin_port=htons(2934), 
sin_addr=inet_addr("")}, [16]) = 3

### all the proxying to/from the backend to the client ...

connect(4, {sa_family=AF_FILE, path="/var/state/ratetrack/ratepostaction"}, 
110) = 0
getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
writev(4, [{"GET / HTTP/1.0\r\nRateUser: testuser\r\nRateURI: 
/testdir/\r\nRateBytes: 739\r\nHost: localhost\r\nConnection: 
close\r\n\r\n", xyz}], 1) = xyz
epoll_wait(11, {{EPOLLOUT, {u32=3081253209, u64=13233881762136338777}}}, 
512, 60000) = 1
gettimeofday({1204859394, 498342}, NULL) = 0

### got here and would have waited 30 seconds for backend to respond, but 
before that happened I did another web request with the browser to the same 

{{EPOLLIN|EPOLLOUT, {u32=3081253125, u64=13831246206168740101}}}, 512, 
59972) = 1
gettimeofday({1204859397, 533816}, NULL) = 0

### In no way attempts to handle the new request. Just keeps waiting for the 
backend post_action handler to respond and finish, only then does it handle 
the new request

This seems a bug to me. A post_action handler shouldn't be able to block the 
handling of new connections to nginx.


More information about the nginx mailing list