Skip to content

Commit 36a3b75

Browse files
committed
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 redis#2264
1 parent 5e8b7e4 commit 36a3b75

File tree

4 files changed

+119
-23
lines changed

4 files changed

+119
-23
lines changed

redis.conf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@
3636
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
3737
daemonize no
3838

39+
# If you run Redis from upstart or systemd, Redis can interact with your
40+
# supervision tree. Options:
41+
# supervised no - no supervision interaction
42+
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
43+
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
44+
# supervised auto - detect upstart or systemd method based on
45+
# UPSTART_JOB or NOTIFY_SOCKET environment variables
46+
# Note: these supervision methods only signal "process is ready."
47+
# They do not enable continuous liveness pings back to your supervisor.
48+
supervised no
49+
3950
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
4051
# default. You can specify a custom pid file location here.
4152
pidfile /var/run/redis.pid

src/config.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ clientBufferLimitsConfig clientBufferLimitsDefaults[REDIS_CLIENT_TYPE_COUNT] = {
6060
* Config file parsing
6161
*----------------------------------------------------------------------------*/
6262

63+
int supervisedToMode(const char *str);
64+
6365
int yesnotoi(char *s) {
6466
if (!strcasecmp(s,"yes")) return 1;
6567
else if (!strcasecmp(s,"no")) return 0;
@@ -533,6 +535,15 @@ void loadServerConfigFromString(char *config) {
533535
goto loaderr;
534536
}
535537
server.notify_keyspace_events = flags;
538+
} else if (!strcasecmp(argv[0],"supervised") && argc == 2) {
539+
int mode = supervisedToMode(argv[1]);
540+
541+
if (mode == -1) {
542+
err = "Invalid option for 'supervised'. "
543+
"Allowed values: 'upstart', 'systemd', 'auto', or 'no'";
544+
goto loaderr;
545+
}
546+
server.supervised_mode = mode;
536547
} else if (!strcasecmp(argv[0],"sentinel")) {
537548
/* argc == 1 is handled by main() as we need to enter the sentinel
538549
* mode ASAP. */
@@ -1022,6 +1033,33 @@ char *maxmemoryToString() {
10221033
return s;
10231034
}
10241035

1036+
int supervisedToMode(const char *str) {
1037+
int mode;
1038+
if (!strcasecmp(str,"upstart")) {
1039+
mode = REDIS_SUPERVISED_UPSTART;
1040+
} else if (!strcasecmp(str,"systemd")) {
1041+
mode = REDIS_SUPERVISED_SYSTEMD;
1042+
} else if (!strcasecmp(str,"auto")) {
1043+
mode = REDIS_SUPERVISED_AUTODETECT;
1044+
} else if (!strcasecmp(str,"no")) {
1045+
mode = REDIS_SUPERVISED_NONE;
1046+
} else {
1047+
mode = -1;
1048+
}
1049+
return mode;
1050+
}
1051+
1052+
char *supervisedToString(void) {
1053+
char *s;
1054+
switch(server.supervised_mode) {
1055+
case REDIS_SUPERVISED_UPSTART: s = "upstart"; break;
1056+
case REDIS_SUPERVISED_SYSTEMD: s = "systemd"; break;
1057+
case REDIS_SUPERVISED_AUTODETECT: s = "auto"; break;
1058+
case REDIS_SUPERVISED_NONE: s = "no"; break;
1059+
default: s = "no"; break;
1060+
}
1061+
return s;
1062+
}
10251063
void configGetCommand(redisClient *c) {
10261064
robj *o = c->argv[2];
10271065
void *replylen = addDeferredMultiBulkLength(c);
@@ -1177,6 +1215,11 @@ void configGetCommand(redisClient *c) {
11771215
addReplyBulkCString(c,s);
11781216
matches++;
11791217
}
1218+
if (stringmatch(pattern,"supervised",0)) {
1219+
addReplyBulkCString(c,"supervised");
1220+
addReplyBulkCString(c,supervisedToString());
1221+
matches++;
1222+
}
11801223
if (stringmatch(pattern,"client-output-buffer-limit",0)) {
11811224
sds buf = sdsempty();
11821225
int j;
@@ -1872,6 +1915,12 @@ int rewriteConfig(char *path) {
18721915
rewriteConfigNumericalOption(state,"hz",server.hz,REDIS_DEFAULT_HZ);
18731916
rewriteConfigYesNoOption(state,"aof-rewrite-incremental-fsync",server.aof_rewrite_incremental_fsync,REDIS_DEFAULT_AOF_REWRITE_INCREMENTAL_FSYNC);
18741917
rewriteConfigYesNoOption(state,"aof-load-truncated",server.aof_load_truncated,REDIS_DEFAULT_AOF_LOAD_TRUNCATED);
1918+
rewriteConfigEnumOption(state,"supervised",server.supervised_mode,
1919+
"upstart", REDIS_SUPERVISED_UPSTART,
1920+
"systemd", REDIS_SUPERVISED_SYSTEMD,
1921+
"auto", REDIS_SUPERVISED_AUTODETECT,
1922+
"no", REDIS_SUPERVISED_NONE,
1923+
NULL, REDIS_SUPERVISED_NONE);
18751924
if (server.sentinel_mode) rewriteConfigSentinelOption(state);
18761925

18771926
/* Step 3: remove all the orphaned lines in the old file, that is, lines

src/redis.c

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,7 @@ void initServerConfig(void) {
14161416
server.syslog_facility = LOG_LOCAL0;
14171417
server.daemonize = REDIS_DEFAULT_DAEMONIZE;
14181418
server.supervised = 0;
1419+
server.supervised_mode = REDIS_SUPERVISED_NONE;
14191420
server.aof_state = REDIS_AOF_OFF;
14201421
server.aof_fsync = REDIS_DEFAULT_AOF_FSYNC;
14211422
server.aof_no_fsync_on_rewrite = REDIS_DEFAULT_AOF_NO_FSYNC_ON_REWRITE;
@@ -3591,52 +3592,60 @@ void redisSetProcTitle(char *title) {
35913592
/*
35923593
* Check whether systemd or upstart have been used to start redis.
35933594
*/
3594-
int redisIsSupervised(void) {
3595+
3596+
int redisSupervisedUpstart(void) {
35953597
const char *upstart_job = getenv("UPSTART_JOB");
3598+
3599+
if (!upstart_job) {
3600+
redisLog(REDIS_WARNING,
3601+
"upstart supervision requested, but UPSTART_JOB not found");
3602+
return 0;
3603+
}
3604+
3605+
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
3606+
raise(SIGSTOP);
3607+
unsetenv("UPSTART_JOB");
3608+
return 1;
3609+
}
3610+
3611+
int redisSupervisedSystemd(void) {
35963612
const char *notify_socket = getenv("NOTIFY_SOCKET");
35973613
int fd = 1;
35983614
struct sockaddr_un su;
35993615
struct iovec iov;
36003616
struct msghdr hdr;
36013617
int sendto_flags = 0;
36023618

3603-
if (upstart_job == NULL && notify_socket == NULL)
3619+
if (!notify_socket) {
3620+
redisLog(REDIS_WARNING,
3621+
"systemd supervision requested, but NOTIFY_SOCKET not found");
36043622
return 0;
3605-
3606-
if (upstart_job != NULL) {
3607-
redisLog(REDIS_NOTICE, "supervised by upstart, will stop to signal readyness");
3608-
raise(SIGSTOP);
3609-
unsetenv("UPSTART_JOB");
3610-
3611-
return 1;
36123623
}
36133624

3614-
/*
3615-
* If we got here, we're supervised by systemd.
3616-
*/
3617-
if ((strchr("@/", notify_socket[0])) == NULL ||
3618-
strlen(notify_socket) < 2)
3625+
if ((strchr("@/", notify_socket[0])) == NULL || strlen(notify_socket) < 2) {
36193626
return 0;
3627+
}
36203628

36213629
redisLog(REDIS_NOTICE, "supervised by systemd, will signal readyness");
3622-
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
3623-
redisLog(REDIS_WARNING, "cannot contact systemd socket %s", notify_socket);
3630+
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
3631+
redisLog(REDIS_WARNING,
3632+
"Can't connect to systemd socket %s", notify_socket);
36243633
return 0;
36253634
}
36263635

3627-
bzero(&su, sizeof(su));
3636+
memset(&su, 0, sizeof(su));
36283637
su.sun_family = AF_UNIX;
36293638
strncpy (su.sun_path, notify_socket, sizeof(su.sun_path) -1);
36303639
su.sun_path[sizeof(su.sun_path) - 1] = '\0';
36313640

36323641
if (notify_socket[0] == '@')
36333642
su.sun_path[0] = '\0';
36343643

3635-
bzero(&iov, sizeof(iov));
3644+
memset(&iov, 0, sizeof(iov));
36363645
iov.iov_base = "READY=1";
36373646
iov.iov_len = strlen("READY=1");
36383647

3639-
bzero(&hdr, sizeof(hdr));
3648+
memset(&hdr, 0, sizeof(hdr));
36403649
hdr.msg_name = &su;
36413650
hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
36423651
strlen(notify_socket);
@@ -3648,14 +3657,34 @@ int redisIsSupervised(void) {
36483657
sendto_flags |= MSG_NOSIGNAL;
36493658
#endif
36503659
if (sendmsg(fd, &hdr, sendto_flags) < 0) {
3651-
redisLog(REDIS_WARNING, "Cannot send notification to systemd");
3660+
redisLog(REDIS_WARNING, "Can't send notification to systemd");
36523661
close(fd);
36533662
return 0;
36543663
}
36553664
close(fd);
36563665
return 1;
36573666
}
36583667

3668+
int redisIsSupervised(int mode) {
3669+
if (mode == REDIS_SUPERVISED_AUTODETECT) {
3670+
const char *upstart_job = getenv("UPSTART_JOB");
3671+
const char *notify_socket = getenv("NOTIFY_SOCKET");
3672+
3673+
if (upstart_job) {
3674+
redisSupervisedUpstart();
3675+
} else if (notify_socket) {
3676+
redisSupervisedSystemd();
3677+
}
3678+
} else if (mode == REDIS_SUPERVISED_UPSTART) {
3679+
return redisSupervisedUpstart();
3680+
} else if (mode == REDIS_SUPERVISED_SYSTEMD) {
3681+
return redisSupervisedSystemd();
3682+
}
3683+
3684+
return 0;
3685+
}
3686+
3687+
36593688
int main(int argc, char **argv) {
36603689
struct timeval tv;
36613690

@@ -3762,8 +3791,8 @@ int main(int argc, char **argv) {
37623791
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");
37633792
}
37643793

3765-
server.supervised = redisIsSupervised();
3766-
int background = server.daemonize && server.supervised == 0;
3794+
server.supervised = redisIsSupervised(server.supervised_mode);
3795+
int background = server.daemonize && !server.supervised;
37673796
if (background) daemonize();
37683797
initServer();
37693798
if (background || server.pidfile) createPidFile();

src/redis.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,12 @@ typedef long long mstime_t; /* millisecond time type. */
313313
#define REDIS_LOG_RAW (1<<10) /* Modifier to log without timestamp */
314314
#define REDIS_DEFAULT_VERBOSITY REDIS_NOTICE
315315

316+
/* Supervision options */
317+
#define REDIS_SUPERVISED_NONE 0
318+
#define REDIS_SUPERVISED_AUTODETECT 1
319+
#define REDIS_SUPERVISED_SYSTEMD 2
320+
#define REDIS_SUPERVISED_UPSTART 3
321+
316322
/* Anti-warning macro... */
317323
#define REDIS_NOTUSED(V) ((void) V)
318324

@@ -740,7 +746,8 @@ struct redisServer {
740746
int active_expire_enabled; /* Can be disabled for testing purposes. */
741747
size_t client_max_querybuf_len; /* Limit for client query buffer length */
742748
int dbnum; /* Total number of configured DBs */
743-
int supervised; /* True if supervised by upstart or systemd */
749+
int supervised; /* 1 if supervised, 0 otherwise. */
750+
int supervised_mode; /* See REDIS_SUPERVISED_* */
744751
int daemonize; /* True if running as a daemon */
745752
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT];
746753
/* AOF persistence */

0 commit comments

Comments
 (0)