summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Truschnigg <johannes@truschnigg.info>2019-04-27 18:07:30 +0200
committermax ulidtko <ulidtko@gmail.com>2019-11-19 18:55:44 +0200
commit641c64ada10404356fc76c0b56a69b32c76f253c (patch)
treea1310ebd0116c69bd3953afcc8590ceb1a52835a
parent45025713a8b284d649af540c0cab2e5af52e1a9f (diff)
downloadredis-641c64ada10404356fc76c0b56a69b32c76f253c.tar.gz
Use libsystemd's sd_notify for communicating redis status to systemd
Instead of replicating a subset of libsystemd's sd_notify(3) internally, use the dynamic library provided by systemd to communicate with the service manager. When systemd supervision was auto-detected or configured, communicate the actual server status (i.e. "Loading dataset", "Waiting for master<->replica sync") to systemd, instead of declaring readiness right after initializing the server process.
-rw-r--r--src/replication.c5
-rw-r--r--src/server.c84
-rw-r--r--src/server.h1
3 files changed, 48 insertions, 42 deletions
diff --git a/src/replication.c b/src/replication.c
index c9a2e0fe1..68dc77a61 100644
--- a/src/replication.c
+++ b/src/replication.c
@@ -1665,6 +1665,11 @@ void readSyncBulkPayload(connection *conn) {
if (server.repl_backlog == NULL) createReplicationBacklog();
serverLog(LL_NOTICE, "MASTER <-> REPLICA sync: Finished with success");
+ if (server.supervised_mode == SUPERVISED_SYSTEMD) {
+ redisCommunicateSystemd("STATUS=MASTER <-> REPLICA sync: Finished with success. Ready to accept connections.\n");
+ redisCommunicateSystemd("READY=1\n");
+ }
+
/* Restart the AOF subsystem now that we finished the sync. This
* will trigger an AOF rewrite, and when done will start appending
* to the new file. */
diff --git a/src/server.c b/src/server.c
index 2e9a329dd..e86f16aa8 100644
--- a/src/server.c
+++ b/src/server.c
@@ -55,6 +55,7 @@
#include <sys/utsname.h>
#include <locale.h>
#include <sys/socket.h>
+#include <dlfcn.h>
/* Our shared "common" objects */
@@ -3651,6 +3652,8 @@ int prepareForShutdown(int flags) {
int nosave = flags & SHUTDOWN_NOSAVE;
serverLog(LL_WARNING,"User requested shutdown...");
+ if (server.supervised_mode == SUPERVISED_SYSTEMD)
+ redisCommunicateSystemd("STOPPING=1\n");
/* Kill all the Lua debugger forked sessions. */
ldbKillForkedSessions();
@@ -3692,6 +3695,8 @@ int prepareForShutdown(int flags) {
/* Create a new RDB file before exiting. */
if ((server.saveparamslen > 0 && !nosave) || save) {
serverLog(LL_NOTICE,"Saving the final RDB snapshot before exiting.");
+ if (server.supervised_mode == SUPERVISED_SYSTEMD)
+ redisCommunicateSystemd("STATUS=Saving the final RDB snapshot\n");
/* Snapshotting. Perform a SYNC SAVE and exit */
rdbSaveInfo rsi, *rsiptr;
rsiptr = rdbPopulateSaveInfo(&rsi);
@@ -3702,6 +3707,8 @@ int prepareForShutdown(int flags) {
* saving aborted, handling special stuff like slaves pending for
* synchronization... */
serverLog(LL_WARNING,"Error trying to save the DB, can't exit.");
+ if (server.supervised_mode == SUPERVISED_SYSTEMD)
+ redisCommunicateSystemd("STATUS=Error trying to save the DB, can't exit.\n");
return C_ERR;
}
}
@@ -4867,13 +4874,11 @@ int redisSupervisedUpstart(void) {
return 1;
}
-int redisSupervisedSystemd(void) {
+int redisCommunicateSystemd(const char *sd_notify_msg) {
const char *notify_socket = getenv("NOTIFY_SOCKET");
- int fd = 1;
- struct sockaddr_un su;
- struct iovec iov;
- struct msghdr hdr;
- int sendto_flags = 0;
+ int (*dl_sd_notify)(int unset_environment, const char *state);
+ char *error;
+ void *handle;
if (!notify_socket) {
serverLog(LL_WARNING,
@@ -4881,47 +4886,28 @@ int redisSupervisedSystemd(void) {
return 0;
}
- if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
- return 0;
- }
-
- serverLog(LL_NOTICE, "supervised by systemd, will signal readiness");
- if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
+ handle = dlopen("libsystemd.so.0", RTLD_LAZY);
+ if (!handle) {
serverLog(LL_WARNING,
- "Can't connect to systemd socket %s", notify_socket);
+ "systemd supervision requested, but could not dlopen() libsystemd.so");
+ (void) dlerror();
return 0;
}
+ (void) dlerror();
- memset(&su, 0, sizeof(su));
- su.sun_family = AF_UNIX;
- strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1);
- su.sun_path[sizeof(su.sun_path) - 1] = '\0';
-
- if (notify_socket[0] == '@')
- su.sun_path[0] = '\0';
+ *(void **)(&dl_sd_notify) = dlsym(handle, "sd_notify");
+ error = dlerror();
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = "READY=1";
- iov.iov_len = strlen("READY=1");
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.msg_name = &su;
- hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
- strlen(notify_socket);
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
-
- unsetenv("NOTIFY_SOCKET");
-#ifdef HAVE_MSG_NOSIGNAL
- sendto_flags |= MSG_NOSIGNAL;
-#endif
- if (sendmsg(fd, &hdr, sendto_flags) < 0) {
- serverLog(LL_WARNING, "Can't send notification to systemd");
- close(fd);
+ if (error != NULL) {
+ serverLog(LL_WARNING,
+ "systemd supervision requested, but could not load sd_notify(3) from libsystemd.so");
+ dlclose(handle);
return 0;
}
- close(fd);
- return 1;
+
+ (void) (*dl_sd_notify)(0, sd_notify_msg);
+ dlclose(handle);
+ return 0;
}
int redisIsSupervised(int mode) {
@@ -4932,12 +4918,17 @@ int redisIsSupervised(int mode) {
if (upstart_job) {
redisSupervisedUpstart();
} else if (notify_socket) {
- redisSupervisedSystemd();
+ 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");
}
} else if (mode == SUPERVISED_UPSTART) {
return redisSupervisedUpstart();
} else if (mode == SUPERVISED_SYSTEMD) {
- return redisSupervisedSystemd();
+ 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;
@@ -5130,6 +5121,15 @@ int main(int argc, char **argv) {
serverLog(LL_NOTICE,"Ready to accept connections");
if (server.sofd > 0)
serverLog(LL_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);
+ if (server.supervised_mode == SUPERVISED_SYSTEMD) {
+ /* XXX TODO is this sufficient to pass readiness control off to readSyncBulkPayload()? */
+ if (!server.masterhost) {
+ redisCommunicateSystemd("STATUS=Ready to accept connections\n");
+ redisCommunicateSystemd("READY=1\n");
+ } else {
+ redisCommunicateSystemd("STATUS=Waiting for MASTER <-> REPLICA sync\n");
+ }
+ }
} else {
InitServerLast();
sentinelIsRunning();
diff --git a/src/server.h b/src/server.h
index ad47fe80b..28aa2085c 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1620,6 +1620,7 @@ uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
void exitFromChild(int retcode);
size_t redisPopcount(void *s, long count);
void redisSetProcTitle(char *title);
+int redisCommunicateSystemd(const char *sd_notify_msg);
/* networking.c -- Networking and Client related operations */
client *createClient(connection *conn);