[PATCH] Keepalive connections now respect lingering_timeout on shutdown

Maxim Dounin mdounin at mdounin.ru
Wed Jul 10 15:25:17 UTC 2024


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1720570370 -10800
#      Wed Jul 10 03:12:50 2024 +0300
# Node ID 3e36eed5bdaf1eec3d069705f197d04ef942b9d4
# Parent  2a847df382320a54c32abd9e64412ac611fcff0c
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.

diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- 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;
     }
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -331,6 +331,8 @@ typedef struct {
 
     ngx_chain_t                      *free;
 
+    ngx_msec_t                        keepalive_timeout;
+
     unsigned                          ssl:1;
     unsigned                          proxy_protocol:1;
 } ngx_http_connection_t;



More information about the nginx-devel mailing list