]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mworker: Add systemd `Type=notify` support
authorTim Duesterhus <tim@bastelstu.be>
Mon, 20 Nov 2017 14:58:35 +0000 (15:58 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 20 Nov 2017 17:39:41 +0000 (18:39 +0100)
This patch adds support for `Type=notify` to the systemd unit.

Supporting `Type=notify` improves both starting as well as reloading
of the unit, because systemd will be let known when the action completed.

See this quote from `systemd.service(5)`:
> Note however that reloading a daemon by sending a signal (as with the
> example line above) is usually not a good choice, because this is an
> asynchronous operation and hence not suitable to order reloads of
> multiple services against each other. It is strongly recommended to
> set ExecReload= to a command that not only triggers a configuration
> reload of the daemon, but also synchronously waits for it to complete.

By making systemd aware of a reload in progress it is able to wait until
the reload actually succeeded.

This patch introduces both a new `USE_SYSTEMD` build option which controls
including the sd-daemon library as well as a `-Ws` runtime option which
runs haproxy in master-worker mode with systemd support.

When haproxy is running in master-worker mode with systemd support it will
send status messages to systemd using `sd_notify(3)` in the following cases:

- The master process forked off the worker processes (READY=1)
- The master process entered the `mworker_reload()` function (RELOADING=1)
- The master process received the SIGUSR1 or SIGTERM signal (STOPPING=1)

Change the unit file to specify `Type=notify` and replace master-worker
mode (`-W`) with master-worker mode with systemd support (`-Ws`).

Future evolutions of this feature could include making use of the `STATUS`
feature of `sd_notify()` to send information about the number of active
connections to systemd. This would require bidirectional communication
between the master and the workers and thus is left for future work.

Makefile
contrib/systemd/haproxy.service.in
include/types/global.h
src/haproxy.c

index 200a5f60d3993df843295835447733947d5c10fa..2a2a21ff95062f82d6d82de21454073945c4251a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@
 #   USE_DEVICEATLAS      : enable DeviceAtlas api.
 #   USE_51DEGREES        : enable third party device detection library from 51Degrees
 #   USE_WURFL            : enable WURFL detection library from Scientiamobile
+#   USE_SYSTEMD          : enable sd_notify() support.
 #
 # Options can be forced by specifying "USE_xxx=1" or can be disabled by using
 # "USE_xxx=" (empty string).
@@ -700,6 +701,12 @@ BUILD_OPTIONS   += $(call ignore_implicit,USE_WURFL)
 OPTIONS_LDFLAGS += $(if $(WURFL_LIB),-L$(WURFL_LIB)) -lwurfl
 endif
 
+ifneq ($(USE_SYSTEMD),)
+BUILD_OPTIONS   += $(call ignore_implicit,USE_SYSTEMD)
+OPTIONS_CFLAGS  += -DUSE_SYSTEMD
+OPTIONS_LDFLAGS += -lsystemd
+endif
+
 ifneq ($(USE_PCRE)$(USE_STATIC_PCRE)$(USE_PCRE_JIT),)
 ifneq ($(USE_PCRE2)$(USE_STATIC_PCRE2)$(USE_PCRE2_JIT),)
 $(error cannot compile both PCRE and PCRE2 support)
index 81b4951df2b94e76c51e1b85e6adda6799a38297..edbd4c292dd589bc1eff300d2859afafe9ccef3a 100644 (file)
@@ -7,12 +7,12 @@ After=network.target
 # socket if you want seamless reloads.
 Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
 ExecStartPre=@SBINDIR@/haproxy -f $CONFIG -c -q
-ExecStart=@SBINDIR@/haproxy -W -f $CONFIG -p $PIDFILE
+ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE
 ExecReload=@SBINDIR@/haproxy -f $CONFIG -c -q
 ExecReload=/bin/kill -USR2 $MAINPID
 KillMode=mixed
 Restart=always
-Type=forking
+Type=notify
 
 [Install]
 WantedBy=multi-user.target
index 6793c83cdfa270181332d862b325d98e1c5b90a1..242b6234a89f77024de37e1be7d3c0be66751f53 100644 (file)
@@ -66,6 +66,7 @@
 
 #define GTUNE_SOCKET_TRANSFER   (1<<8)
 #define GTUNE_EXIT_ONFAILURE     (1<<9)
+#define GTUNE_USE_SYSTEMD        (1<<10)
 
 /* Access level for a stats socket */
 #define ACCESS_LVL_NONE     0
index ba5a4b208553f14cf67aeebf4c4ca6399212801e..b39a95fe35dac60205cf6ca7616cc2d0e07cdfa7 100644 (file)
@@ -61,6 +61,9 @@
 #ifdef DEBUG_FULL
 #include <assert.h>
 #endif
+#if defined(USE_SYSTEMD)
+#include <systemd/sd-daemon.h>
+#endif
 
 #include <common/base64.h>
 #include <common/cfgparse.h>
@@ -404,6 +407,9 @@ static void usage(char *name)
                "        -V enters verbose mode (disables quiet mode)\n"
                "        -D goes daemon ; -C changes to <dir> before loading files.\n"
                "        -W master-worker mode.\n"
+#if defined(USE_SYSTEMD)
+               "        -Ws master-worker mode with systemd notify support.\n"
+#endif
                "        -q quiet mode : don't display messages\n"
                "        -c check mode : only check config files and exit\n"
                "        -n sets the maximum total # of connections (%d)\n"
@@ -635,6 +641,10 @@ static void mworker_reload()
 
        mworker_block_signals();
        mworker_unregister_signals();
+#if defined(USE_SYSTEMD)
+       if (global.tune.options & GTUNE_USE_SYSTEMD)
+               sd_notify(0, "RELOADING=1");
+#endif
        setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
 
        /* compute length  */
@@ -698,6 +708,11 @@ static void mworker_wait()
 
 restart_wait:
 
+#if defined(USE_SYSTEMD)
+       if (global.tune.options & GTUNE_USE_SYSTEMD)
+               sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid());
+#endif
+
        mworker_register_signals();
        mworker_unblock_signals();
 
@@ -710,6 +725,11 @@ restart_wait:
                                /* should reach there only if it fail */
                                goto restart_wait;
                        } else {
+#if defined(USE_SYSTEMD)
+                               if ((global.tune.options & GTUNE_USE_SYSTEMD) && (sig == SIGUSR1 || sig == SIGTERM)) {
+                                       sd_notify(0, "STOPPING=1");
+                               }
+#endif
                                Warning("Exiting Master process...\n");
                                mworker_kill(sig);
                                mworker_unregister_signals();
@@ -1342,6 +1362,15 @@ static void init(int argc, char **argv)
                                arg_mode |= MODE_CHECK;
                        else if (*flag == 'D')
                                arg_mode |= MODE_DAEMON;
+                       else if (*flag == 'W' && flag[1] == 's') {
+                               arg_mode |= MODE_MWORKER;
+#if defined(USE_SYSTEMD)
+                               global.tune.options |= GTUNE_USE_SYSTEMD;
+#else
+                               Alert("master-worker mode with systemd support (-Ws) requested, but not compiled. Use master-worker mode (-W) if you are not using Type=notify in your unit file or recompile with USE_SYSTEMD=1.\n\n");
+                               usage(progname);
+#endif
+                       }
                        else if (*flag == 'W')
                                arg_mode |= MODE_MWORKER;
                        else if (*flag == 'q')