post_action, just send http request, not fcgi - more questions + post_action bug?
Igor Sysoev
is at rambler-co.ru
Mon Mar 10 23:03:10 MSK 2008
On Fri, Mar 07, 2008 at 02:17:37PM +1100, Rob Mueller wrote:
> >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 http://127.0.0.1:2350;
> > }
> >
> >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?
"proxy_pass_request_body off" is right way to do this.
As well as proxy_pass_request_headers, it was created to include banners
via SSI.
> 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?
Yes, nginx does not send post_action content to a client.
> 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
> response
>
> 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("192.168.110.1")}, [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
> epoll_wait(11,
>
> ### 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
> uri...
>
> {{EPOLLIN|EPOLLOUT, {u32=3081253125, u64=13831246206168740101}}}, 512,
> 59972) = 1
> gettimeofday({1204859397, 533816}, NULL) = 0
> epoll_wait(11,
>
> ### 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.
post_action does not block new connections, but it blocks current connection.
nginx handles post_action in context of request and connection, so it
does not close connection to a client before going to post_action.
And "keepalive_timeout 0" will not help.
If you run another browser you are will get response immidiately.
--
Igor Sysoev
http://sysoev.ru/en/
More information about the nginx
mailing list