]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: server: close new idle conns if server in maintenance
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 8 Aug 2025 15:17:26 +0000 (17:17 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 28 Aug 2025 12:55:18 +0000 (14:55 +0200)
Currently, when a server is set on maintenance mode, its idle connection
are scheduled for purge. However, this does not prevent currently used
connection to become idle later on, even if the server is still off.

Change this behavior : an idle connection is now rejected by the server
if it is in maintenance. This is implemented with a new condition in
srv_add_to_idle_list() which returns an error value. In this case, muxes
stream detach callback will immediately free the connection.

A similar change is also performed in each MUX and SSL I/O handlers and
in conn_notify_mux(). An idle connection is not reinserted in its idle
list if server is in maintenance, but instead it is immediately freed.

src/connection.c
src/mux_fcgi.c
src/mux_h1.c
src/mux_h2.c
src/mux_spop.c
src/server.c
src/ssl_sock.c

index be03b0d47e072445cd7827ea136bc419d699fb0f..6dbca2c12f1deff0afd5b4ebd5c96612ec0f5256 100644 (file)
@@ -213,6 +213,13 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
                        goto done;
 
                if (conn_in_list) {
+                       if (srv->cur_admin & SRV_ADMF_MAINT) {
+                               /* Do not store an idle conn if server in maintenance. */
+                               conn->mux->destroy(conn->ctx);
+                               ret = -1;
+                               goto done;
+                       }
+
                        HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
                        _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
                        HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
index 0b143b89329772c809d2584ac0224dd1a1e036b8..949ef19c1cf3bffd156a5a991acf0bc9f503dc05 100644 (file)
@@ -3091,11 +3091,21 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
        if (!ret && conn_in_list) {
                struct server *srv = __objt_server(conn->target);
 
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
-               _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               }
+               else {
+                       /* Do not store an idle conn if server in maintenance. */
+                       goto release;
+               }
        }
        return t;
+
+ release:
+       fcgi_release(fconn);
+       return NULL;
 }
 
 /* callback called on any event by the connection handler.
index a8a6efa93c189a8b6fa2c18a7ff4f94a3de89f37..8aeec3931f21f15f2c4dae29d9fd9a6fbb294a17 100644 (file)
@@ -4328,11 +4328,21 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
        if (!ret && conn_in_list) {
                struct server *srv = __objt_server(conn->target);
 
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
-               _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               }
+               else {
+                       /* Do not store an idle conn if server in maintenance. */
+                       goto release;
+               }
        }
        return t;
+
+ release:
+       h1_release(h1c);
+       return NULL;
 }
 
 static int h1_wake(struct connection *conn)
index 9ae45d2611fe6fd10a7931ae743f445cd9eede9d..bf678e26e8db3e972e41771b9fc70cf62c4c863e 100644 (file)
@@ -4995,14 +4995,25 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
        if (!ret && conn_in_list) {
                struct server *srv = __objt_server(conn->target);
 
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
-               _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               }
+               else {
+                       /* Do not store an idle conn if server in maintenance. */
+                       goto release;
+               }
        }
 
-leave:
+ leave:
        TRACE_LEAVE(H2_EV_H2C_WAKE);
        return t;
+
+ release:
+       TRACE_LEAVE(H2_EV_H2C_WAKE);
+       h2_release(h2c);
+       return NULL;
 }
 
 /* callback called on any event by the connection handler.
index 95000e02bb9730516300741f1c9ee1289331c34a..77ee3a2425455098b11eab06a164073d4147654f 100644 (file)
@@ -2587,11 +2587,21 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
        if (!ret && conn_in_list) {
                struct server *srv = __objt_server(conn->target);
 
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
-               _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               }
+               else {
+                       /* Do not store an idle conn if server in maintenance. */
+                       goto release;
+               }
        }
        return t;
+
+ release:
+       spop_release(spop_conn);
+       return NULL;
 }
 
 /* callback called on any event by the connection handler.
index b469b7ca85e62b5d2d079e1f651b54addc1ea60b..d736362f70be901f9f85040db07005fa80b4c977 100644 (file)
@@ -7327,6 +7327,7 @@ int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_saf
         */
        if (!(conn->flags & CO_FL_PRIVATE) &&
            srv && srv->pool_purge_delay > 0 &&
+           !(srv->cur_admin & SRV_ADMF_MAINT) &&
            ((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) &&
            ha_used_fds < global.tune.pool_high_count &&
            (srv->max_idle_conns == -1 || srv->max_idle_conns > srv->curr_idle_conns) &&
index fc4e5a6024bdc398b8e0b102e931095c800cb559..9342bd6d124fdab79fa99b8299aa4c1d940765b3 100644 (file)
@@ -6478,12 +6478,22 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
 #endif
 leave:
        if (!ret && conn_in_list) {
-               struct server *srv = objt_server(conn->target);
+               struct server *srv = __objt_server(conn->target);
 
-               TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
-               HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
-               _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
-               HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
+                       TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
+                       HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+                       _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
+                       HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+               }
+               else {
+                       /* Do not store an idle conn if server in maintenance. */
+
+                       /* Connection is idle which means MUX layer is already initialized. */
+                       BUG_ON(!conn->mux);
+                       conn->mux->destroy(conn->ctx);
+                       t = NULL;
+               }
        }
        TRACE_LEAVE(SSL_EV_CONN_IO_CB, conn);
        return t;