MEDIUM: server: close new idle conns if server in maintenance

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.
This commit is contained in:
Amaury Denoyelle 2025-08-08 17:17:26 +02:00
parent f234b40cde
commit 67df6577ff
7 changed files with 77 additions and 18 deletions

View File

@ -213,6 +213,13 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
goto done; goto done;
if (conn_in_list) { 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); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);

View File

@ -3091,11 +3091,21 @@ struct task *fcgi_io_cb(struct task *t, void *ctx, unsigned int state)
if (!ret && conn_in_list) { if (!ret && conn_in_list) {
struct server *srv = __objt_server(conn->target); struct server *srv = __objt_server(conn->target);
if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); 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; return t;
release:
fcgi_release(fconn);
return NULL;
} }
/* callback called on any event by the connection handler. /* callback called on any event by the connection handler.

View File

@ -4328,11 +4328,21 @@ struct task *h1_io_cb(struct task *t, void *ctx, unsigned int state)
if (!ret && conn_in_list) { if (!ret && conn_in_list) {
struct server *srv = __objt_server(conn->target); struct server *srv = __objt_server(conn->target);
if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); 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; return t;
release:
h1_release(h1c);
return NULL;
} }
static int h1_wake(struct connection *conn) static int h1_wake(struct connection *conn)

View File

@ -4995,14 +4995,25 @@ struct task *h2_io_cb(struct task *t, void *ctx, unsigned int state)
if (!ret && conn_in_list) { if (!ret && conn_in_list) {
struct server *srv = __objt_server(conn->target); struct server *srv = __objt_server(conn->target);
if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); 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); TRACE_LEAVE(H2_EV_H2C_WAKE);
return t; return t;
release:
TRACE_LEAVE(H2_EV_H2C_WAKE);
h2_release(h2c);
return NULL;
} }
/* callback called on any event by the connection handler. /* callback called on any event by the connection handler.

View File

@ -2587,11 +2587,21 @@ static struct task *spop_io_cb(struct task *t, void *ctx, unsigned int state)
if (!ret && conn_in_list) { if (!ret && conn_in_list) {
struct server *srv = __objt_server(conn->target); struct server *srv = __objt_server(conn->target);
if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); 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; return t;
release:
spop_release(spop_conn);
return NULL;
} }
/* callback called on any event by the connection handler. /* callback called on any event by the connection handler.

View 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) && if (!(conn->flags & CO_FL_PRIVATE) &&
srv && srv->pool_purge_delay > 0 && srv && srv->pool_purge_delay > 0 &&
!(srv->cur_admin & SRV_ADMF_MAINT) &&
((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) && ((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) &&
ha_used_fds < global.tune.pool_high_count && ha_used_fds < global.tune.pool_high_count &&
(srv->max_idle_conns == -1 || srv->max_idle_conns > srv->curr_idle_conns) && (srv->max_idle_conns == -1 || srv->max_idle_conns > srv->curr_idle_conns) &&

View File

@ -6478,13 +6478,23 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
#endif #endif
leave: leave:
if (!ret && conn_in_list) { if (!ret && conn_in_list) {
struct server *srv = objt_server(conn->target); struct server *srv = __objt_server(conn->target);
if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn); 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); HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST); _srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock); 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); TRACE_LEAVE(SSL_EV_CONN_IO_CB, conn);
return t; return t;
} }