changeset 9307:3c71158f5a34 default tip

Keepalive connections now respect lingering_timeout on shutdown. During graceful shutdown keepalive connections are now closed only after at least lingering_timeout of inactivity. To do so, c->idle is only set on keepalive connections after lingering_timeout expires. This ensures that the connection close race will less likely result in connections being reset when a client sends a request at the same time when the connection is closed by ngx_close_idle_connections() during graceful shutdown.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 31 Jul 2024 17:50:58 +0300
parents e46e1ea89ccd
children
files src/http/ngx_http_request.c src/http/ngx_http_request.h
diffstat 2 files changed, 35 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -3099,6 +3099,7 @@ ngx_http_set_keepalive(ngx_http_request_
 {
     int                        tcp_nodelay;
     ngx_buf_t                 *b, *f;
+    ngx_msec_t                 timer;
     ngx_chain_t               *cl, *ln;
     ngx_event_t               *rev, *wev;
     ngx_connection_t          *c;
@@ -3299,10 +3300,19 @@ ngx_http_set_keepalive(ngx_http_request_
     r->http_state = NGX_HTTP_KEEPALIVE_STATE;
 #endif
 
-    c->idle = 1;
     ngx_reusable_connection(c, 1);
 
-    ngx_add_timer(rev, clcf->keepalive_timeout);
+    if (clcf->lingering_close
+        && clcf->lingering_timeout > 0)
+    {
+        timer = ngx_min(clcf->keepalive_timeout, clcf->lingering_timeout);
+        hc->keepalive_timeout = clcf->keepalive_timeout - timer;
+        ngx_add_timer(rev, timer);
+
+    } else {
+        c->idle = 1;
+        ngx_add_timer(rev, clcf->keepalive_timeout);
+    }
 
     if (rev->ready) {
         ngx_post_event(rev, &ngx_posted_events);
@@ -3313,16 +3323,32 @@ ngx_http_set_keepalive(ngx_http_request_
 static void
 ngx_http_keepalive_handler(ngx_event_t *rev)
 {
-    size_t             size;
-    ssize_t            n;
-    ngx_buf_t         *b;
-    ngx_connection_t  *c;
+    size_t                  size;
+    ssize_t                 n;
+    ngx_buf_t              *b;
+    ngx_connection_t       *c;
+    ngx_http_connection_t  *hc;
 
     c = rev->data;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http keepalive handler");
 
-    if (rev->timedout || c->close) {
+    if (rev->timedout) {
+        if (c->idle || ngx_exiting) {
+            ngx_http_close_connection(c);
+            return;
+        }
+
+        hc = c->data;
+
+        c->idle = 1;
+        rev->timedout = 0;
+        ngx_add_timer(rev, hc->keepalive_timeout);
+
+        return;
+    }
+
+    if (c->close) {
         ngx_http_close_connection(c);
         return;
     }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -332,6 +332,8 @@ typedef struct {
 
     ngx_chain_t                      *free;
 
+    ngx_msec_t                        keepalive_timeout;
+
     unsigned                          ssl:1;
     unsigned                          proxy_protocol:1;
 } ngx_http_connection_t;