2 questions on send_timeout (maybe bugs)

Wu Bingzheng wubingzheng at 163.com
Fri May 20 07:58:20 MSD 2011


Hi Maxim,

1.
I am so sorry that I made a big mistake on question 1.
Nginx didn't detect the downstream breaking, because I use "proxy_ignore_client_abort on;".
So Nginx works correctlly. I am so sorry about it.


2.
For question 2.
You said that :
>Note also that in debug log you provided nginx correctly times out 
>after 20s from last send.

That's because I set the send_timeout as 10s. I am sorry that I did not make clear of that.


You can reproduce the doubled timeout easy:

[server] using nginx-1.0.0, without any addon module. in nginx.conf:

    server {
        listen       5821;
        proxy_buffering off; #must in non-buffering mode
        send_timeout 10;

        location / {
            proxy_pass http://sourceserver;
        }
    }



[client] you can run this simple python script:

  #!/usr/bin/python
  import socket
  import time
  s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  s.connect((127.0.0.1, 5821))
  s.send("GET /data/something HTTP/1.0\r\n\r\n")
  buf = s.recv(100)
  print buf
  time.sleep(100)



Then, in access.log, you will find that the request is finished in 20s.


Best Regads,
Wu








At 2011-05-19 19:38:42,"Maxim Dounin" <mdounin at mdounin.ru> wrote:

>Hello!
>
>On Thu, May 19, 2011 at 10:39:43AM +0800, Wu Bingzheng wrote:
>
>> Hi Maxim,
>> 
>> Thanks for your answer. But I am still confused.
>> 
>> 
>> At 2011-05-18 21:35:07,"Maxim Dounin" <mdounin at mdounin.ru> wrote:
>> 
>> >Hello!
>> >
>> >On Wed, May 18, 2011 at 05:15:00PM +0800, Wu Bingzheng wrote:
>> >
>> >> hi all,
>> >> 
>> >> 
>> >> I meet 2 question when using nginx 1.0.0.
>> >> 
>> >> 
>> >> Question1.
>> >> 
>> >> what happens if the downstream connection breaks, before all 
>> >> data sent to the client?
>> >> 
>> >> 1. get client's request
>> >> 2. set handler: r->read_event_handle=ngx_http_block_reading
>> >> 3. send data to client, and blocked ( 
>> >> write_filter.c:c->send_chain() returns non-NULL or non-error), 
>> >> and go back to epoll_wait
>> >> 4. HERE, the downstream breaks
>> >> 5. epoll detect the breaking, so epoll_wait() continues in 
>> >> ngx_epoll_process_events(), where the revents==EPOLL_IN | 
>> >> EPOLL_ERR | EPOLL_HUP. So we call rev->handler(), which calls 
>> >> r->read_event_handle, which dose nothing. AS A RESULT, the 
>> >> downstream breaking was not detected by nginx !!!
>> >
>> >Here write event handler will be called.  While standard 
>> >ngx_http_writer() is in use - it will call output filter chain and 
>> >detect error.  Else it's up to active handler to correctly handle 
>> >this, e.g. standard upstream modules (proxy/fastcgi/...) may 
>> >either terminate request immediately or wait for full upstream 
>> >response depending on various settings (proxy_ignore_client_abort, 
>> >proxy_cache/proxy_store enabled).
>> >
>> 
>> You said the write handler will be called. But if a connection 
>> is break, revents returned by epoll_wait() is 'EPOLL_IN |  
>> EPOLL_ERR | EPOLL_HUP', and no EPOLL_OUT in revents. So I think 
>> the write-handler will NOT be called.
>
>Ah, ok, it looks like I was wrong here.  Write handler will be 
>only called if there are no EPOLLIN flag in revents, and this is 
>probably wrong assuming EPOLLHUP follows the same semantics as 
>POLLHUP[1], i.e.
>
>POLLHUP
>...  This event and POLLOUT are mutually-exclusive; a stream can 
>never be writable if a hangup has occurred. ...
>
>Could you please provide detailed instructions to reproduce the 
>problem, preferably with standard modules involved?
>
>[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
>
>> The FACT is, in my server, there are many many access logs whose 
>> time-taken are 40.001s. (send_timeout is 20s, and this is a 
>> music online server, so many people re-choose a song before the 
>> current song finishs, which means the downstream breaks before 
>> nginx sends all data).
>> 
>> I add 2 debug log in ngx_epoll_process_events(), and copy part 
>> of the debug log here.
>
>Just a side note: mostly same information may be seen at global 
>level debug log.
>
>[...]
>
>> >> I set 'send_timeout' as 20s, but nginx timeouts in 40s actually.
>> >> 
>> >> 1. in 
>> >> src/http/ngx_http_upstream.c[line2448]:ngx_http_upstream_process_non_buffered_request(), 
>> >> a timer is added;
>> >> 2. after that timer timeout, in 
>> >> src/http/ngx_http_request.c[line2179]:ngx_http_set_write_handler(), 
>> >> another timer is added again.
>> >> 
>> >> so the send_timeout is doubled.
>> >
>> >Timeout is re-set on each send operation, and expected to be 
>> >triggered when nothing happens during send_timeout.
>> 
>> So, you think that, I set 'send_timeout' as 20s, but nginx 
>> actually timeout in 40s is right and expected?
>
>It should timeout in 20s after last send.  Whether request time 
>of 40s is wrong or not depends on many factors, but the code you 
>pointed out looks fine.
>
>Note also that in debug log you provided nginx correctly times out 
>after 20s from last send.
>
>Maxim Dounin




More information about the nginx mailing list