From d638b058341c0cc09871848848ed0f59a2a23fc8 Mon Sep 17 00:00:00 2001 From: Yossi Gottlieb Date: Tue, 17 Nov 2020 12:52:49 +0200 Subject: [PATCH] Improve and clean up supervised process support. (#8036) * Configuration file default should now be "auto". * Expose "process_supervised" as an info field. * Log messages improvements (clarify required systemd config, report auto-detected supervision mode, etc.) * Set server.supervised properly, so it can take precedence of "daemonize" configuration. * Produce clear warning if systemd is detected/requested but executable is compiled without support for it, instead of silently ignoring. * Handle systemd notification error on startup, and turn off supervised mode if it failed. --- redis.conf | 9 ++++- src/server.c | 101 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/redis.conf b/redis.conf index d28c17b6..dcb5f624 100644 --- a/redis.conf +++ b/redis.conf @@ -228,6 +228,7 @@ tcp-keepalive 300 # By default Redis does not run as a daemon. Use 'yes' if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +# When Redis is supervised by upstart or systemd, this parameter has no impact. daemonize no # If you run Redis from upstart or systemd, Redis can interact with your @@ -236,11 +237,17 @@ daemonize no # supervised upstart - signal upstart by putting Redis into SIGSTOP mode # requires "expect stop" in your upstart job config # supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# on startup, and updating Redis status on a regular +# basis. # supervised auto - detect upstart or systemd method based on # UPSTART_JOB or NOTIFY_SOCKET environment variables # Note: these supervision methods only signal "process is ready." # They do not enable continuous pings back to your supervisor. -supervised no +# +# The default is "no". To run under upstart/systemd, you can simply uncomment +# the line below: +# +# supervised auto # If a pid file is specified, Redis writes it where specified at startup # and removes it at exit. diff --git a/src/server.c b/src/server.c index cef9f718..1ce6b68b 100644 --- a/src/server.c +++ b/src/server.c @@ -4247,11 +4247,20 @@ sds genRedisInfoString(const char *section) { static int call_uname = 1; static struct utsname name; char *mode; + char *supervised; if (server.cluster_enabled) mode = "cluster"; else if (server.sentinel_mode) mode = "sentinel"; else mode = "standalone"; + if (server.supervised) { + if (server.supervised_mode == SUPERVISED_UPSTART) supervised = "upstart"; + else if (server.supervised_mode == SUPERVISED_SYSTEMD) supervised = "systemd"; + else supervised = "unknown"; + } else { + supervised = "no"; + } + if (sections++) info = sdscat(info,"\r\n"); if (call_uname) { @@ -4275,6 +4284,7 @@ sds genRedisInfoString(const char *section) { "atomicvar_api:%s\r\n" "gcc_version:%i.%i.%i\r\n" "process_id:%I\r\n" + "process_supervised:%s\r\n" "run_id:%s\r\n" "tcp_port:%i\r\n" "uptime_in_seconds:%I\r\n" @@ -4300,6 +4310,7 @@ sds genRedisInfoString(const char *section) { 0,0,0, #endif (int64_t) getpid(), + supervised, server.runid, server.port ? server.port : server.tls_port, (int64_t)uptime, @@ -5224,62 +5235,82 @@ void redisSetCpuAffinity(const char *cpulist) { #endif } -/* - * Check whether systemd or upstart have been used to start redis. - */ +/* Send a notify message to systemd. Returns sd_notify return code which is + * a positive number on success. */ +int redisCommunicateSystemd(const char *sd_notify_msg) { +#ifdef HAVE_LIBSYSTEMD + int ret = sd_notify(0, sd_notify_msg); -int redisSupervisedUpstart(void) { + if (ret == 0) + serverLog(LL_WARNING, "systemd supervision error: NOTIFY_SOCKET not found!"); + else if (ret < 0) + serverLog(LL_WARNING, "systemd supervision error: sd_notify: %d", ret); + return ret; +#else + UNUSED(sd_notify_msg); + return 0; +#endif +} + +/* Attempt to set up upstart supervision. Returns 1 if successful. */ +static int redisSupervisedUpstart(void) { const char *upstart_job = getenv("UPSTART_JOB"); if (!upstart_job) { serverLog(LL_WARNING, - "upstart supervision requested, but UPSTART_JOB not found"); + "upstart supervision requested, but UPSTART_JOB not found!"); return 0; } - serverLog(LL_NOTICE, "supervised by upstart, will stop to signal readiness"); + serverLog(LL_NOTICE, "supervised by upstart, will stop to signal readiness."); raise(SIGSTOP); unsetenv("UPSTART_JOB"); return 1; } -int redisCommunicateSystemd(const char *sd_notify_msg) { - const char *notify_socket = getenv("NOTIFY_SOCKET"); - if (!notify_socket) { - serverLog(LL_WARNING, - "systemd supervision requested, but NOTIFY_SOCKET not found"); - } - - #ifdef HAVE_LIBSYSTEMD - (void) sd_notify(0, sd_notify_msg); - #else - UNUSED(sd_notify_msg); - #endif +/* Attempt to set up systemd supervision. Returns 1 if successful. */ +static int redisSupervisedSystemd(void) { +#ifndef HAVE_LIBSYSTEMD + serverLog(LL_WARNING, + "systemd supervision requested or auto-detected, but Redis is compiled without libsystemd support!"); return 0; +#else + if (redisCommunicateSystemd("STATUS=Redis is loading...\n") <= 0) + return 0; + serverLog(LL_NOTICE, + "Supervised by systemd. Please make sure you set appropriate values for TimeoutStartSec and TimeoutStopSec in your service unit."); + return 1; +#endif } int redisIsSupervised(int mode) { - if (mode == SUPERVISED_AUTODETECT) { - const char *upstart_job = getenv("UPSTART_JOB"); - const char *notify_socket = getenv("NOTIFY_SOCKET"); + int ret = 0; - if (upstart_job) { - redisSupervisedUpstart(); - } else if (notify_socket) { - server.supervised_mode = SUPERVISED_SYSTEMD; - serverLog(LL_WARNING, - "WARNING auto-supervised by systemd - you MUST set appropriate values for TimeoutStartSec and TimeoutStopSec in your service unit."); - return redisCommunicateSystemd("STATUS=Redis is loading...\n"); + if (mode == SUPERVISED_AUTODETECT) { + if (getenv("UPSTART_JOB")) { + serverLog(LL_VERBOSE, "Upstart supervision detected."); + mode = SUPERVISED_UPSTART; + } else if (getenv("NOTIFY_SOCKET")) { + serverLog(LL_VERBOSE, "Systemd supervision detected."); + mode = SUPERVISED_SYSTEMD; } - } else if (mode == SUPERVISED_UPSTART) { - return redisSupervisedUpstart(); - } else if (mode == SUPERVISED_SYSTEMD) { - serverLog(LL_WARNING, - "WARNING supervised by systemd - you MUST set appropriate values for TimeoutStartSec and TimeoutStopSec in your service unit."); - return redisCommunicateSystemd("STATUS=Redis is loading...\n"); } - return 0; + switch (mode) { + case SUPERVISED_UPSTART: + ret = redisSupervisedUpstart(); + break; + case SUPERVISED_SYSTEMD: + ret = redisSupervisedSystemd(); + break; + default: + break; + } + + if (ret) + server.supervised_mode = mode; + + return ret; } int iAmMaster(void) {