summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Stancliff <matt@genges.com>2015-01-08 15:22:33 -0500
committerMatt Stancliff <matt@genges.com>2015-01-09 15:19:18 -0500
commit36a3b75355bd5aea9e34889918c5b78fb79586e4 (patch)
treeda11ffc8680536ad53ef75f29663bfa626a41cd1
parent5e8b7e4f356c2908bb3389e2df09473e290acae8 (diff)
downloadredis-36a3b75355bd5aea9e34889918c5b78fb79586e4.tar.gz
Supervise redis processes only if configured
Adds configuration option 'supervised [no | upstart | systemd | auto]' Also removed 'bzero' from the previous implementation because it's 2015. (We could actually statically initialize those structs, but clang throws an invalid warning when we try, so it looks bad even though it isn't bad.) Fixes #2264
-rw-r--r--redis.conf11
-rw-r--r--src/config.c49
-rw-r--r--src/redis.c73
-rw-r--r--src/redis.h9
4 files changed, 119 insertions, 23 deletions
diff --git a/redis.conf b/redis.conf
index b2ee853cd..38e258698 100644
--- a/redis.conf
+++ b/redis.conf
@@ -36,6 +36,17 @@
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no
+# If you run Redis from upstart or systemd, Redis can interact with your
+# supervision tree. Options:
+# supervised no - no supervision interaction
+# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
+# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
+# 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 liveness pings back to your supervisor.
+supervised no
+
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile /var/run/redis.pid
diff --git a/src/config.c b/src/config.c
index b0245954c..8255a56b7 100644
--- a/src/config.c
+++ b/src/config.c
@@ -60,6 +60,8 @@ clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = {
* Config file parsing
*----------------------------------------------------------------------------*/
+int supervisedToMode(const char *str);
+
int yesnotoi(char *s) {
if (!strcasecmp(s,"yes")) return 1;
else if (!strcasecmp(s,"no")) return 0;
@@ -533,6 +535,15 @@ void loadServerConfigFromString(char *config) {
goto loaderr;
}
server.notify_keyspace_events = flags;
+ } else if (!strcasecmp(argv[0],"supervised") && argc == 2) {
+ int mode = supervisedToMode(argv[1]);
+
+ if (mode == -1) {
+ err = "Invalid option for 'supervised'. "
+ "Allowed values: 'upstart', 'systemd', 'auto', or 'no'";
+ goto loaderr;
+ }
+ server.supervised_mode = mode;
} else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */
@@ -1022,6 +1033,33 @@ char *maxmemoryToString() {
return s;
}
+int supervisedToMode(const char *str) {
+ int mode;
+ if (!strcasecmp(str,"upstart")) {
+ mode = REDIS_SUPERVISED_UPSTART;
+ } else if (!strcasecmp(str,"systemd")) {
+ mode = REDIS_SUPERVISED_SYSTEMD;
+ } else if (!strcasecmp(str,"auto")) {
+ mode = REDIS_SUPERVISED_AUTODETECT;
+ } else if (!strcasecmp(str,"no")) {
+ mode = REDIS_SUPERVISED_NONE;
+ } else {
+ mode = -1;
+ }
+ return mode;
+}
+
+char *supervisedToString(void) {
+ char *s;
+ switch(server.supervised_mode) {
+ case REDIS_SUPERVISED_UPSTART: s = "upstart"; break;
+ case REDIS_SUPERVISED_SYSTEMD: s = "systemd"; break;
+ case REDIS_SUPERVISED_AUTODETECT: s = "auto"; break;
+ case REDIS_SUPERVISED_NONE: s = "no"; break;
+ default: s = "no"; break;
+ }
+ return s;
+}
void configGetCommand(redisClient *c) {
robj *o = c->argv[2];
void *replylen = addDeferredMultiBulkLength(c);
@@ -1177,6 +1215,11 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString(c,s);
matches++;
}
+ if (stringmatch(pattern,"supervised",0)) {
+ addReplyBulkCString(c,"supervised");
+ addReplyBulkCString(c,supervisedToString());
+ matches++;
+ }
if (stringmatch(pattern,"client-output-buffer-limit",0)) {
sds buf = sdsempty();
int j;
@@ -1872,6 +1915,12 @@ int rewriteConfig(char *path) {
rewriteConfigNumericalOption(state,"hz",server.hz,REDIS_DEFAULT_HZ);
rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC);
rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,REDIS_DEFAULT_AOF_LOAD_TRUNCATED);
+ rewriteConfigEnumOption(state,"supervised",server.supervised_mode,
+ "upstart", REDIS_SUPERVISED_UPSTART,
+ "systemd", REDIS_SUPERVISED_SYSTEMD,
+ "auto", REDIS_SUPERVISED_AUTODETECT,
+ "no", REDIS_SUPERVISED_NONE,
+ NULL, REDIS_SUPERVISED_NONE);
if (server.sentinel_mode) rewriteConfigSentinelOption(state);
/* Step 3: remove all the orphaned lines in the old file, that is, lines
diff --git a/src/redis.c b/src/redis.c
index fd0d39bb8..13df8d28e 100644
--- a/src/redis.c
+++ b/src/redis.c
@@ -1416,6 +1416,7 @@ void initServerConfig(void) {
server.syslog_facility = LOG_LOCAL0;
server.daemonize = REDIS_DEFAULT_DAEMONIZE;
server.supervised = 0;
+ server.supervised_mode = REDIS_SUPERVISED_NONE;
server.aof_state = REDIS_AOF_OFF;
server.aof_fsync = REDIS_DEFAULT_AOF_FSYNC;
server.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
@@ -3591,8 +3592,23 @@ void redisSetProcTitle(char *title) {
/*
* Check whether systemd or upstart have been used to start redis.
*/
-int redisIsSupervised(void) {
+
+int redisSupervisedUpstart(void) {
const char *upstart_job = getenv("UPSTART_JOB");
+
+ if (!upstart_job) {
+ redisLog(REDIS_WARNING,
+ "upstart supervision requested, but UPSTART_JOB not found");
+ return 0;
+ }
+
+ redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
+ raise(SIGSTOP);
+ unsetenv("UPSTART_JOB");
+ return 1;
+}
+
+int redisSupervisedSystemd(void) {
const char *notify_socket = getenv("NOTIFY_SOCKET");
int fd = 1;
struct sockaddr_un su;
@@ -3600,31 +3616,24 @@ int redisIsSupervised(void) {
struct msghdr hdr;
int sendto_flags = 0;
- if (upstart_job == NULL && notify_socket == NULL)
+ if (!notify_socket) {
+ redisLog(REDIS_WARNING,
+ "systemd supervision requested, but NOTIFY_SOCKET not found");
return 0;
-
- if (upstart_job != NULL) {
- redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
- raise(SIGSTOP);
- unsetenv("UPSTART_JOB");
-
- return 1;
}
- /*
- * If we got here, we're supervised by systemd.
- */
- if ((strchr("@/", notify_socket[0])) == NULL ||
- strlen(notify_socket) < 2)
+ if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
return 0;
+ }
redisLog(REDIS_NOTICE, "supervised by systemd, will signal readyness");
- if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- redisLog(REDIS_WARNING, "cannot contact systemd socket %s", notify_socket);
+ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
+ redisLog(REDIS_WARNING,
+ "Can't connect to systemd socket %s", notify_socket);
return 0;
}
- bzero(&su, sizeof(su));
+ 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';
@@ -3632,11 +3641,11 @@ int redisIsSupervised(void) {
if (notify_socket[0] == '@')
su.sun_path[0] = '\0';
- bzero(&iov, sizeof(iov));
+ memset(&iov, 0, sizeof(iov));
iov.iov_base = "READY=1";
iov.iov_len = strlen("READY=1");
- bzero(&hdr, sizeof(hdr));
+ memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = &su;
hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
strlen(notify_socket);
@@ -3648,7 +3657,7 @@ int redisIsSupervised(void) {
sendto_flags |= MSG_NOSIGNAL;
#endif
if (sendmsg(fd, &hdr, sendto_flags) < 0) {
- redisLog(REDIS_WARNING, "Cannot send notification to systemd");
+ redisLog(REDIS_WARNING, "Can't send notification to systemd");
close(fd);
return 0;
}
@@ -3656,6 +3665,26 @@ int redisIsSupervised(void) {
return 1;
}
+int redisIsSupervised(int mode) {
+ if (mode == REDIS_SUPERVISED_AUTODETECT) {
+ const char *upstart_job = getenv("UPSTART_JOB");
+ const char *notify_socket = getenv("NOTIFY_SOCKET");
+
+ if (upstart_job) {
+ redisSupervisedUpstart();
+ } else if (notify_socket) {
+ redisSupervisedSystemd();
+ }
+ } else if (mode == REDIS_SUPERVISED_UPSTART) {
+ return redisSupervisedUpstart();
+ } else if (mode == REDIS_SUPERVISED_SYSTEMD) {
+ return redisSupervisedSystemd();
+ }
+
+ return 0;
+}
+
+
int main(int argc, char **argv) {
struct timeval tv;
@@ -3762,8 +3791,8 @@ int main(int argc, char **argv) {
redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");
}
- server.supervised = redisIsSupervised();
- int background = server.daemonize && server.supervised == 0;
+ server.supervised = redisIsSupervised(server.supervised_mode);
+ int background = server.daemonize && !server.supervised;
if (background) daemonize();
initServer();
if (background || server.pidfile) createPidFile();
diff --git a/src/redis.h b/src/redis.h
index 54046ef27..89d97f55e 100644
--- a/src/redis.h
+++ b/src/redis.h
@@ -313,6 +313,12 @@ typedef long long mstime_t; /* millisecond time type. */
#define REDIS_LOG_RAW (1<<10) /* Modifier to log without timestamp */
#define REDIS_DEFAULT_VERBOSITY REDIS_NOTICE
+/* Supervision options */
+#define REDIS_SUPERVISED_NONE 0
+#define REDIS_SUPERVISED_AUTODETECT 1
+#define REDIS_SUPERVISED_SYSTEMD 2
+#define REDIS_SUPERVISED_UPSTART 3
+
/* Anti-warning macro... */
#define REDIS_NOTUSED(V) ((void) V)
@@ -740,7 +746,8 @@ struct redisServer {
int active_expire_enabled; /* Can be disabled for testing purposes. */
size_t client_max_querybuf_len; /* Limit for client query buffer length */
int dbnum; /* Total number of configured DBs */
- int supervised; /* True if supervised by upstart or systemd */
+ int supervised; /* 1 if supervised, 0 otherwise. */
+ int supervised_mode; /* See REDIS_SUPERVISED_* */
int daemonize; /* True if running as a daemon */
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT];
/* AOF persistence */