Hi all, Based on [0] and in particular:
"Despite it being against the "spirit" of systemd, this is perhaps the cleanest and most reliable: have systemd poll whatever service the daemon is supposed to provide. For example, if the service is starting sshd on port 22, systemd could repeatedly try connecting to port 22, with exponential backoff, until it succeeds. This approach requires no modification to existing daemons, and if implemented correctly, would have minimal cost (only at daemon start time) in cpu load and startup latency." I added a fifo listener mode for respawn. It will sit there waiting for the specified fifo to become readable and it will restart the given program. It discards all input on the fifo. The monitoring tool does not exist yet but it can be written separately and then simply do a dummy write to the respawn fifo. Rate-limiting might have to happen somewhere but I'd like to keep respawn dumb. The number of writes do not correspond 1-1 with the number of invocations. If the monitoring program writes too fast, the writes will most probably be coalesced as far as the respawn tool is concerned. So it is likely for N writes very close together that it will trigger only 1 invocation of the program. What do you think? Cheers, sin [0] http://ewontfix.com/15/
>From bcb98c9736725eccfdaf23dfb53cbebc2d7973be Mon Sep 17 00:00:00 2001 From: sin <s...@2f30.org> Date: Mon, 21 Apr 2014 11:48:09 +0100 Subject: [PATCH] Implement fifo listener mode for respawn --- respawn.1 | 8 +++++++- respawn.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/respawn.1 b/respawn.1 index f9d68a1..05ad86b 100644 --- a/respawn.1 +++ b/respawn.1 @@ -2,7 +2,7 @@ .SH NAME \fBrespawn\fR - Spawn the given command repeatedly .SH SYNOPSIS -\fBrespawn\fR [\fB-d\fI N\fR] \fIcmd\fR [\fIargs...\fR] +\fBrespawn\fR [\fB-l\fI fifo\fR] [\fB-d\fI N\fR] \fIcmd\fR [\fIargs...\fR] .SH DESCRIPTION \fBrespawn\fR spawns the given \fIcmd\fR in a new session repeatedly. @@ -10,3 +10,9 @@ repeatedly. .TP \fB-d\fR Set the delay between invocations of \fIcmd\fR. It defaults to 0. +.TP +\fB-l\fR +Listen on the specified \fIfifo\fR for writes. For each write +spawn a new instance of \fIcmd\fR. This can be used in conjunction +with a process supervisor to restart a particular program. The \fB-l\fR +and \fB-d\fR options are incompatible. All writes are discarded. diff --git a/respawn.c b/respawn.c index 453c534..30ca01d 100644 --- a/respawn.c +++ b/respawn.c @@ -1,6 +1,12 @@ /* See LICENSE file for copyright and license details. */ +#include <fcntl.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> @@ -9,20 +15,28 @@ static void usage(void) { - eprintf("usage: respawn [-d N] cmd [args...]\n"); + eprintf("usage: respawn [-l fifo] [-d N] cmd [args...]\n"); } int main(int argc, char *argv[]) { + char *fifo = NULL; + unsigned int delay = 0; pid_t pid; + char buf[BUFSIZ]; int savederrno; - unsigned int delay = 0; + int fd; + ssize_t n; + fd_set rdfd; ARGBEGIN { case 'd': delay = estrtol(EARGF(usage()), 0); break; + case 'l': + fifo = EARGF(usage()); + break; default: usage(); } ARGEND; @@ -30,7 +44,30 @@ main(int argc, char *argv[]) if(argc < 1) usage(); + if (fifo && delay > 0) + usage(); + + if (fifo) { + fd = open(fifo, O_RDWR | O_NONBLOCK); + if (fd < 0) + eprintf("open %s:", fifo); + } + while (1) { + if (fifo) { + FD_ZERO(&rdfd); + FD_SET(fd, &rdfd); + n = select(fd + 1, &rdfd, NULL, NULL, NULL); + if (n < 0) + eprintf("select:"); + if (n == 0 || FD_ISSET(fd, &rdfd) == 0) + continue; + while ((n = read(fd, buf, sizeof(buf))) > 0) + ; + if (n < 0) + if (errno != EAGAIN) + eprintf("read %s:", fifo); + } pid = fork(); if (pid < 0) eprintf("fork:"); @@ -47,7 +84,8 @@ main(int argc, char *argv[]) waitpid(pid, NULL, 0); break; } - sleep(delay); + if (!fifo) + sleep(delay); } /* not reachable */ return EXIT_SUCCESS; -- 1.9.2