]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: startup: split sending oldpids_sig logic for standalone and mworker modes
authorValentine Krasnobaeva <vkrasnobaeva@haproxy.com>
Thu, 3 Oct 2024 09:16:35 +0000 (11:16 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 16 Oct 2024 20:02:39 +0000 (22:02 +0200)
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.

src/cli.c
src/haproxy.c

index 11fc1b5616afcd087bed40710838ab63d6cad032..a18ff8f23b24feab8a4b96f6b51a9d86f0de3908 100644 (file)
--- 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;
 }
index cbbbb3728012579359198c78c6d0ac98c1f6d4a9..9407761752103fb4b4b89cfd60c105b3ae8e12fa 100644 (file)
@@ -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());