Merge pull request #2134 from pyr/feature/supervised-init

Support daemon supervision by upstart or systemd
This commit is contained in:
Salvatore Sanfilippo 2014-12-11 14:39:09 +01:00
commit 9c385ada22
3 changed files with 72 additions and 3 deletions

View File

@ -857,7 +857,7 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
" Suspect RAM error? Use redis-server --test-memory to verify it.\n\n"
);
/* free(messages); Don't call free() with possibly corrupted memory. */
if (server.daemonize) unlink(server.pidfile);
if (server.daemonize && server.supervised == 0) unlink(server.pidfile);
/* Make sure we exit with the right signal at the end. So for instance
* the core will be dumped if enabled. */

View File

@ -46,6 +46,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <limits.h>
#include <float.h>
#include <math.h>
@ -1413,6 +1414,7 @@ void initServerConfig(void) {
server.syslog_ident = zstrdup(REDIS_DEFAULT_SYSLOG_IDENT);
server.syslog_facility = LOG_LOCAL0;
server.daemonize = REDIS_DEFAULT_DAEMONIZE;
server.supervised = 0;
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;
@ -3574,6 +3576,70 @@ void redisSetProcTitle(char *title) {
#endif
}
/*
* Check whether systemd or upstart have been used to start redis.
*/
int redisIsSupervised(void) {
const char *upstart_job = getenv("UPSTART_JOB");
const char *notify_socket = getenv("NOTIFY_SOCKET");
int fd = 1;
struct sockaddr_un su;
struct iovec iov;
struct msghdr hdr;
if (upstart_job == NULL && notify_socket == NULL)
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)
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);
return 0;
}
bzero(&su, 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';
bzero(&iov, sizeof(iov));
iov.iov_base = "READY=1";
iov.iov_len = strlen("READY=1");
bzero(&hdr, 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");
if (sendmsg(fd, &hdr, MSG_NOSIGNAL) < 0) {
redisLog(REDIS_WARNING, "cannot send notification to systemd");
close(fd);
return 0;
}
close(fd);
return 1;
}
int main(int argc, char **argv) {
struct timeval tv;
@ -3653,9 +3719,11 @@ int main(int argc, char **argv) {
} else {
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");
}
if (server.daemonize) daemonize();
server.supervised = redisIsSupervised();
if (server.daemonize && server.supervised == 0) daemonize();
initServer();
if (server.daemonize) createPidFile();
if (server.daemonize && server.supervised == 0) createPidFile();
redisSetProcTitle(argv[0]);
redisAsciiArt();

View File

@ -733,6 +733,7 @@ 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 daemonize; /* True if running as a daemon */
clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_TYPE_COUNT];
/* AOF persistence */