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 a new `USE_SYSTEMD` option which controls including the sd-daemon library. When `USE_SYSTEMD` is enabled and haproxy is running in mworker mode it will send status messages to systemd using `sd_notify()` 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) Status messages are not sent when not using the mworker mode, because using mworker is recommended when using systemd. Change the unit file to specify `Type=notify` as well as `KillSignal=USR1` to support cleaner shutdowns. Systemd will kill haproxy using SIGKILL if connections remain after 90 seconds (by default). Remove KillSignal=USR1 if the SIGKILL is undesired. 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 | 6 ++++++ contrib/systemd/haproxy.service.in | 3 ++- src/haproxy.c | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 200a5f60d..e1eab0c2e 100644 --- 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). @@ -608,6 +609,11 @@ endif OPTIONS_OBJS += src/ssl_sock.o endif +ifneq ($(USE_SYSTEMD),) +OPTIONS_CFLAGS += -DUSE_SYSTEMD +OPTIONS_LDFLAGS += -lsystemd +endif + # The private cache option affect the way the shctx is built ifneq ($(USE_PRIVATE_CACHE),) OPTIONS_CFLAGS += -DUSE_PRIVATE_CACHE diff --git a/contrib/systemd/haproxy.service.in b/contrib/systemd/haproxy.service.in index 81b4951df..895e3b036 100644 --- a/contrib/systemd/haproxy.service.in +++ b/contrib/systemd/haproxy.service.in @@ -11,8 +11,9 @@ ExecStart=@SBINDIR@/haproxy -W -f $CONFIG -p $PIDFILE ExecReload=@SBINDIR@/haproxy -f $CONFIG -c -q ExecReload=/bin/kill -USR2 $MAINPID KillMode=mixed +KillSignal=USR1 Restart=always -Type=forking +Type=notify [Install] WantedBy=multi-user.target diff --git a/src/haproxy.c b/src/haproxy.c index ba5a4b208..63c29023d 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -61,6 +61,9 @@ #ifdef DEBUG_FULL #include <assert.h> #endif +#ifdef USE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif #include <common/base64.h> #include <common/cfgparse.h> @@ -635,6 +638,9 @@ static void mworker_reload() mworker_block_signals(); mworker_unregister_signals(); +#if USE_SYSTEMD + sd_notify(0, "RELOADING=1"); +#endif setenv("HAPROXY_MWORKER_REEXEC", "1", 1); /* compute length */ @@ -682,6 +688,7 @@ static void mworker_reload() return; alloc_error: + Warning("Failed to reexecute the master processs [%d]: Cannot allocate memory\n", pid); return; } @@ -698,6 +705,10 @@ static void mworker_wait() restart_wait: +#if USE_SYSTEMD + sd_notifyf(0, "READY=1\nMAINPID=%lu", (unsigned long)getpid()); +#endif + mworker_register_signals(); mworker_unblock_signals(); @@ -710,6 +721,11 @@ restart_wait: /* should reach there only if it fail */ goto restart_wait; } else { +#if USE_SYSTEMD + if (sig == SIGUSR1 || sig == SIGTERM) { + sd_notify(0, "STOPPING=1"); + } +#endif Warning("Exiting Master process...\n"); mworker_kill(sig); mworker_unregister_signals(); -- 2.15.0