From: Valentine Krasnobaeva Date: Thu, 3 Oct 2024 09:16:35 +0000 (+0200) Subject: MEDIUM: startup: split sending oldpids_sig logic for standalone and mworker modes X-Git-Tag: v3.1-dev10~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=81dbc2c2e27fbd312e956c873a7c3145edde1c87;p=thirdparty%2Fhaproxy.git MEDIUM: startup: split sending oldpids_sig logic for standalone and mworker modes Before refactoring the master-worker mode, in all runtime modes, when the new process successfully parsed its configuration and bound to sockets, it sent either SIGUSR1 or SIGTERM to the previous one in order to terminate it. Let's keep this logic as is for the standalone mode. In addition, in standalone mode we need to send the signal to old process before calling set_identity(), because in set_identity() effective user or group may change. So, the order is important here. In case of master-worker mode after refactoring, master terminates the previous worker by itself up to receiving "READY" status from the new one in _send_status(). Master also sets at this moment HAPROXY_LOAD_SUCCESS env variable and checks, if there are some other workers to terminate with max_reloads exceeded. So, now in master-worker mode we terminate old workers only, when the new one has successfully done all initialization steps and has sent "READY" status to master. --- diff --git a/src/cli.c b/src/cli.c index 11fc1b5616..a18ff8f23b 100644 --- a/src/cli.c +++ b/src/cli.c @@ -2495,6 +2495,8 @@ static int _send_status(char **args, char *payload, struct appctx *appctx, void kill(proc->pid, oldpids_sig); } } + setenv("HAPROXY_LOAD_SUCCESS", "1", 1); + ha_notice("Loading success.\n"); return 1; } diff --git a/src/haproxy.c b/src/haproxy.c index cbbbb37280..9407761752 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -3546,16 +3546,6 @@ int main(int argc, char **argv) } } - if (nb_oldpids && !master) - nb_oldpids = tell_old_pids(oldpids_sig); - - /* Send a SIGTERM to workers who have a too high reloads number. - * master=1 means that fork() was done before. So, at this stage we already - * have at least one new worker with reloads=0, which is bound to sockets. - */ - if (master) - mworker_kill_max_reloads(SIGTERM); - /* Note that any error at this stage will be fatal because we will not * be able to restart the old pids. */ @@ -3610,8 +3600,6 @@ int main(int argc, char **argv) global.mode &= ~MODE_VERBOSE; global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */ } - setenv("HAPROXY_LOAD_SUCCESS", "1", 1); - ha_notice("Loading success.\n"); proc_self->failedreloads = 0; /* reset the number of failure */ mworker_loop(); #if defined(USE_OPENSSL) && !defined(OPENSSL_NO_DH) @@ -3660,6 +3648,15 @@ int main(int argc, char **argv) } ha_free(&global.chroot); + + /* In master-worker mode master sends TERM to previous workers up to + * receiving status READY + */ + if (!(global.mode & MODE_MWORKER) && nb_oldpids) { + nb_oldpids = tell_old_pids(oldpids_sig); + } + + /* oldpids_sig was sent to the previous process, can change uid/gid now */ set_identity(argv[0]); /* set_identity() above might have dropped LSTCHK_NETADM or/and @@ -3796,6 +3793,46 @@ int main(int argc, char **argv) /* when multithreading we need to let only the thread 0 handle the signals */ haproxy_unblock_signals(); + /* send "READY" message to remove status PROC_O_INIT for the newly forked worker, + * master will send TERM to the previous in _send_status() + */ + if (global.mode & MODE_MWORKER) { + struct mworker_proc *proc; + int sock_pair[2]; + char *msg = NULL; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sock_pair) == -1) { + ha_alert("[%s.main()] Cannot create socketpair to update the new worker state\n", + argv[0]); + + exit(1); + } + + list_for_each_entry(proc, &proc_list, list) { + if (proc->pid == -1) + break; + } + + if (send_fd_uxst(proc->ipc_fd[1], sock_pair[0]) == -1) { + ha_alert("[%s.main()] Cannot transfer connection fd %d over the sockpair@%d\n", + argv[0], sock_pair[0], proc->ipc_fd[1]); + close(sock_pair[0]); + close(sock_pair[1]); + + exit(1); + } + close(sock_pair[0]); + + memprintf(&msg, "_send_status READY %d\n", getpid()); + if (send(sock_pair[1], msg, strlen(msg), 0) != strlen(msg)) { + ha_alert("[%s.main()] Failed to send READY status to master\n", argv[0]); + + exit(1); + } + close(sock_pair[1]); + ha_free(&msg); + } + #if defined(USE_SYSTEMD) if (global.tune.options & GTUNE_USE_SYSTEMD) sd_notifyf(0, "READY=1\nMAINPID=%lu\nSTATUS=Ready.\n", (unsigned long)getpid());