From: Valentine Krasnobaeva Date: Wed, 2 Oct 2024 12:48:01 +0000 (+0200) Subject: MINOR: mworker/cli: add _send_status to support state transition X-Git-Tag: v3.1-dev10~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b73a278df4eb0465c96587b69532934745225276;p=thirdparty%2Fhaproxy.git MINOR: mworker/cli: add _send_status to support state transition In the new master-worker architecture, when a worker process is forked and successfully initialized it needs somehow to communicate its "READY" state to the master, in order to terminate the previous worker and workers, that might exceeded max_reloads counter. So, let's implement for this a new master CLI _send_status command. A new worker can send its status string "READY" to the master, when it's about entering to the run poll loop, thus it can start to receive data. In _send_status() in the master context we update the status of the new worker: PROC_O_INIT flag is withdrawn. When TERM signal is sent to a worker, worker terminates and this triggers the mworker_catch_sigchld() handler in master. This handler deletes the exiting process entry from the processes list. In _send_status() we loop over the processes list twice. At the first time, in order to stop workers that exceeded the max_reloads counter. At the second time, in order to stop the worker forked before the last reload. In the corner case, when max_reloads=1, we avoid to send SIGTERM twice to the same worker by setting sigterm_sent flag during the first loop. --- diff --git a/include/haproxy/global.h b/include/haproxy/global.h index 17cfff3ae9..f5c2628d1e 100644 --- a/include/haproxy/global.h +++ b/include/haproxy/global.h @@ -35,6 +35,7 @@ extern int unstoppable_jobs; /* # of active jobs that can't be stopped during extern int active_peers; /* # of active peers (connection attempts and successes) */ extern int connected_peers; /* # of really connected peers */ extern int nb_oldpids; /* contains the number of old pids found */ +extern int oldpids_sig; /* signal to sent in order to stop the previous (old) process */ extern const int zero; extern const int one; extern const struct linger nolinger; diff --git a/include/haproxy/mworker.h b/include/haproxy/mworker.h index 0251a9de27..72c5f94a12 100644 --- a/include/haproxy/mworker.h +++ b/include/haproxy/mworker.h @@ -17,6 +17,7 @@ #include #include +extern int max_reloads; extern struct mworker_proc *proc_self; /* master CLI configuration (-S flag) */ extern struct list mworker_cli_conf; diff --git a/src/cli.c b/src/cli.c index bbd11c1d12..11fc1b5616 100644 --- a/src/cli.c +++ b/src/cli.c @@ -2463,6 +2463,42 @@ static int cli_parse_simple(char **args, char *payload, struct appctx *appctx, v return 1; } +static int _send_status(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct mworker_proc *proc; + int pid; + + BUG_ON((strcmp(args[0], "_send_status") != 0), + "Triggered in _send_status by unsupported command name.\n"); + + pid = atoi(args[2]); + + list_for_each_entry(proc, &proc_list, list) { + /* update status of the new worker */ + if (proc->pid == pid) + proc->options &= ~PROC_O_INIT; + /* send TERM to workers, which have exceeded max_reloads counter */ + if (max_reloads != -1) { + if ((proc->options & PROC_O_TYPE_WORKER) && + (proc->options & PROC_O_LEAVING) && + (proc->reloads > max_reloads) && (proc->pid > 0)) { + kill(proc->pid, SIGTERM); + } + + } + } + /* stop previous worker process, if it wasn't signaled during max reloads check */ + list_for_each_entry(proc, &proc_list, list) { + if ((proc->options & PROC_O_TYPE_WORKER) && + (proc->options & PROC_O_LEAVING) && + (proc->reloads >= 1)) { + kill(proc->pid, oldpids_sig); + } + } + + return 1; +} + void pcli_write_prompt(struct stream *s) { struct buffer *msg = get_trash_chunk(); @@ -3594,6 +3630,7 @@ static struct cli_kw_list cli_kws = {{ },{ { { "operator", NULL }, "operator : lower the level of the current CLI session to operator", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER}, { { "user", NULL }, "user : lower the level of the current CLI session to user", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER}, { { "wait", NULL }, "wait {-h|} cond [args...] : wait the specified delay or condition (-h to see list)", cli_parse_wait, cli_io_handler_wait, cli_release_wait, NULL }, + { { "_send_status", NULL }, NULL, _send_status, NULL, NULL, NULL, ACCESS_MASTER_ONLY }, {{},} }}; diff --git a/src/haproxy.c b/src/haproxy.c index d163998620..cbbbb37280 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -238,7 +238,7 @@ char *check_condition = NULL; /* check condition passed to -cc */ */ #define MAX_START_RETRIES 200 static int *oldpids = NULL; -static int oldpids_sig; /* use USR1 or TERM */ +int oldpids_sig; /* use USR1 or TERM */ /* Path to the unix socket we use to retrieve listener sockets from the old process */ static const char *old_unixsocket; diff --git a/src/mworker.c b/src/mworker.c index 46211c222f..431935852c 100644 --- a/src/mworker.c +++ b/src/mworker.c @@ -46,7 +46,7 @@ #endif static int exitcode = -1; -static int max_reloads = -1; /* number max of reloads a worker can have until they are killed */ +int max_reloads = INT_MAX; /* max number of reloads a worker can have until they are killed */ struct mworker_proc *proc_self = NULL; /* process structure of current process */ struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf); /* master CLI configuration (-S flag) */