From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS30633 207.244.64.0/18 X-Spam-Status: No, score=-0.1 required=3.0 tests=AWL,BAYES_00, RCVD_IN_BL_SPAMCOP_NET,RCVD_IN_XBL,RDNS_NONE,SPF_FAIL,SPF_HELO_FAIL shortcircuit=no autolearn=no version=3.3.2 X-Original-To: yahns-public@yhbt.net Received: from 80x24.org (unknown [207.244.70.35]) by dcvr.yhbt.net (Postfix) with ESMTP id D223C633829 for ; Wed, 27 Apr 2016 00:27:18 +0000 (UTC) From: Eric Wong To: yahns-public@yhbt.net Subject: [PATCH 4/5] proxy_http_response: do not persist upstream on slow clients Date: Wed, 27 Apr 2016 00:27:03 +0000 Message-Id: <20160427002704.10660-5-e@80x24.org> In-Reply-To: <20160427002704.10660-1-e@80x24.org> References: <20160427002704.10660-1-e@80x24.org> List-Id: For slow clients, we want to be able to drop the connection to the upstream as soon as we are done buffering and not waste resources by leaving it in an :ignore state. We also need to remember the client for the fdmap to prevent shutdowns. Ugh, this is really hard to test locally. --- lib/yahns/proxy_http_response.rb | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/yahns/proxy_http_response.rb b/lib/yahns/proxy_http_response.rb index e551323..3462e40 100644 --- a/lib/yahns/proxy_http_response.rb +++ b/lib/yahns/proxy_http_response.rb @@ -56,6 +56,7 @@ def wait_on_upstream(req_res, alive, wbuf) :wait_readable # self remains in :ignore, wait on upstream end + # start streaming the response once upstream is done sending headers to us. # returns :wait_readable if we need to read more from req_res # returns :ignore if we yield control to the client(self) # returns nil if completely done @@ -177,9 +178,9 @@ def proxy_response_start(res, tip, kcar, req_res) end end - return proxy_busy_mod_done(alive) unless wbuf - req_res.resbuf = wbuf - proxy_busy_mod_blocked(wbuf, wbuf.busy) + # all done reading response from upstream, req_res will be discarded + # when we return nil: + wbuf ? proxy_busy_mod_blocked(wbuf, wbuf.busy) : proxy_busy_mod_done(alive) rescue => e proxy_err_response(502, req_res, e, wbuf) end @@ -247,7 +248,7 @@ def proxy_response_finish(kcar, wbuf, req_res) end busy = wbuf.busy and return proxy_busy_mod_blocked(wbuf, busy) - proxy_busy_mod_done(wbuf.wbuf_persist) # returns nil + proxy_busy_mod_done(wbuf.wbuf_persist) # returns nil to close req_res end def proxy_wait_next(qflags) @@ -288,23 +289,23 @@ def proxy_busy_mod_done(alive) when :close then close end - nil # close the req_res, too + nil # signal close for ReqRes#yahns_step end def proxy_busy_mod_blocked(wbuf, busy) - q = Thread.current[:yahns_queue] # we are completely done reading and buffering the upstream response, # but have not completely written the response to the client, # yield control to the client socket: @state = wbuf - case busy - when :wait_readable then q.queue_mod(self, Yahns::Queue::QEV_RD) - when :wait_writable then q.queue_mod(self, Yahns::Queue::QEV_WR) - else - abort "BUG: invalid wbuf.busy: #{busy.inspect}" - end - # no touching self after queue_mod - :ignore + proxy_wait_next(case busy + when :wait_readable then Yahns::Queue::QEV_RD + when :wait_writable then Yahns::Queue::QEV_WR + else + abort "BUG: invalid wbuf.busy: #{busy.inspect}" + end) + # no touching self after proxy_wait_next, we may be running + # HttpClient#yahns_step in a different thread at this point + nil # signal close for ReqRes#yahns_step end # n.b.: we can use String#size for optimized dispatch under YARV instead -- EW