Download raw body.
graceful gotwebd stop
This patch changes the way gotwebd reacts to the TERM signal, allowing
any running requests to complete before gotwebd terminates.
While gotwebd does not need to support configuration reloading we should
be taking better care of in-flight requests while stopping gotwebd. Because
once gotsysd supports gotwebd, gotsys.conf changes can happen at any moment
and require gotsysd to restart gotwebd. I would like to avoid disrupting
in-flight requests and sending "500 internal server error" to clients.
The idea is to have the existing gotwebd instance step away from FastCGi
and login sockets, allowing a new instance of gotwebd to take them over,
while the previous instance finishes serving responses to its own clients.
In a future patch I plan to add a control socket to gotwebd which gotsysd
will use to send a stop request and receive an ackknowledgement once all
sockets have been closed by gotwebd and are ready for reuse.
ok?
M gotwebd/auth.c | 3+ 1-
M gotwebd/fcgi.c | 3+ 1-
M gotwebd/gotweb.c | 3+ 1-
M gotwebd/gotwebd.c | 14+ 0-
M gotwebd/gotwebd.h | 1+ 0-
M gotwebd/login.c | 28+ 4-
M gotwebd/sockets.c | 48+ 7-
7 files changed, 100 insertions(+), 14 deletions(-)
commit - f8c15ec8a9ddce2f08959da8a558e2f50b8738b8
commit + 3865fac52c80823e0147e500c27787097b9d0928
blob - 7a7f27f7ca9352028b2f3268554e61dbcd06b73e
blob + 3e9cee3c275c4af7cd66b09401c857dac8177c95
--- gotwebd/auth.c
+++ gotwebd/auth.c
@@ -100,8 +100,10 @@ auth_sighdlr(int sig, short event, void *arg)
break;
case SIGCHLD:
break;
- case SIGINT:
case SIGTERM:
+ /* continue until the parent exits */
+ break;
+ case SIGINT:
auth_shutdown();
break;
default:
blob - 01e5003ac8ede257607fe188eab2161e67dcae4e
blob + 15a0de5387f3beba35baa991838f86100d51a553
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
@@ -99,8 +99,10 @@ fcgi_sighdlr(int sig, short event, void *arg)
break;
case SIGCHLD:
break;
- case SIGINT:
case SIGTERM:
+ /* continue until the parent exits */
+ break;
+ case SIGINT:
fcgi_shutdown();
break;
default:
blob - f1002b8b938177ae95c844cfb196955ad824a0a4
blob + 4f10d5b34758e3295506e6968f6484005cde9612
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
@@ -1874,8 +1874,10 @@ gotweb_sighdlr(int sig, short event, void *arg)
break;
case SIGCHLD:
break;
- case SIGINT:
case SIGTERM:
+ /* continue until the parent exits */
+ break;
+ case SIGINT:
gotweb_shutdown();
break;
default:
blob - 38dae76d2223e3d613a2588c2d45c1016115083e
blob + f868bed8cfb869337fbd6d4150b9ca347187f066
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
@@ -423,6 +423,18 @@ gotwebd_dispatch_gotweb(int fd, short event, void *arg
}
}
+static void
+gotwebd_stop(void)
+{
+ if (main_compose_sockets(gotwebd_env, GOTWEBD_IMSG_CTL_STOP,
+ -1, NULL, 0) == -1)
+ fatal("send_imsg GOTWEBD_IMSG_CTL_STOP");
+
+ if (main_compose_login(gotwebd_env, GOTWEBD_IMSG_CTL_STOP,
+ -1, NULL, 0) == -1)
+ fatal("send_imsg GOTWEBD_IMSG_CTL_STOP");
+}
+
void
gotwebd_sighdlr(int sig, short event, void *arg)
{
@@ -439,6 +451,8 @@ gotwebd_sighdlr(int sig, short event, void *arg)
log_info("%s: ignoring SIGUSR1", __func__);
break;
case SIGTERM:
+ gotwebd_stop();
+ break;
case SIGINT:
gotwebd_shutdown();
break;
blob - 892c1cb41050f6c7bf46f99e16faad73265e9d2c
blob + b15f41142f74f4762fc71d191f488305088de5ce
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
@@ -149,6 +149,7 @@ enum imsg_type {
GOTWEBD_IMSG_CFG_DONE,
GOTWEBD_IMSG_CTL_PIPE,
GOTWEBD_IMSG_CTL_START,
+ GOTWEBD_IMSG_CTL_STOP,
GOTWEBD_IMSG_LOGIN_SECRET,
GOTWEBD_IMSG_AUTH_SECRET,
GOTWEBD_IMSG_AUTH_CONF,
blob - 9504381f3d7a57fcce332e523404ead0eb3ebe74
blob + 7cad84cee74bf07fc1a726a883a768f6a4ae69dd
--- gotwebd/login.c
+++ gotwebd/login.c
@@ -56,6 +56,7 @@ struct gotwebd_login_client {
static volatile int client_cnt;
static int inflight;
+static volatile int stopping;
static char login_token_secret[32];
@@ -411,6 +412,22 @@ login_shutdown(void)
}
static void
+login_stop(void)
+{
+ struct gotwebd *env = gotwebd_env;
+
+ stopping = 1;
+
+ if (env->iev_gotsh) {
+ evtimer_del(&env->login_pause_ev);
+ event_del(&env->iev_gotsh->ev);
+ close(env->iev_gotsh->ibuf.fd);
+ env->iev_gotsh->ibuf.fd = -1;
+ imsgbuf_clear(&env->iev_gotsh->ibuf);
+ }
+}
+
+static void
login_sighdlr(int sig, short event, void *arg)
{
switch (sig) {
@@ -425,8 +442,10 @@ login_sighdlr(int sig, short event, void *arg)
break;
case SIGCHLD:
break;
- case SIGINT:
case SIGTERM:
+ login_stop();
+ break;
+ case SIGINT:
login_shutdown();
break;
default:
@@ -603,7 +622,7 @@ login_accept(int fd, short event, void *arg)
backoff.tv_sec = 1;
backoff.tv_usec = 0;
- if (event_add(&iev->ev, NULL) == -1) {
+ if (!stopping && event_add(&iev->ev, NULL) == -1) {
log_warn("event_add");
return;
}
@@ -624,7 +643,8 @@ login_accept(int fd, short event, void *arg)
case EMFILE:
case ENFILE:
event_del(&iev->ev);
- evtimer_add(&env->login_pause_ev, &backoff);
+ if (!stopping)
+ evtimer_add(&env->login_pause_ev, &backoff);
return;
default:
log_warn("accept");
@@ -766,6 +786,9 @@ login_dispatch_main(int fd, short event, void *arg)
case GOTWEBD_IMSG_CTL_START:
login_launch(env);
break;
+ case GOTWEBD_IMSG_CTL_STOP:
+ login_stop();
+ break;
case GOTWEBD_IMSG_LOGIN_SECRET:
if (imsg_get_data(&imsg, login_token_secret,
sizeof(login_token_secret)) == -1)
@@ -793,7 +816,8 @@ accept_paused(int fd, short event, void *arg)
{
struct gotwebd *env = gotwebd_env;
- event_add(&env->iev_gotsh->ev, NULL);
+ if (!stopping)
+ event_add(&env->iev_gotsh->ev, NULL);
}
void
blob - dfc46f68407be06d91de5ec11f3b91c189d4ec8a
blob + 387e6c57b105661f9840264b1240b2880aba9517
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
@@ -66,6 +66,7 @@
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
static volatile int client_cnt;
+static volatile int stopping;
static struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
@@ -148,7 +149,8 @@ cleanup_request(struct request *c)
del_request(c);
- event_add(&c->sock->ev, NULL);
+ if (!stopping)
+ event_add(&c->sock->ev, NULL);
if (evtimer_initialized(&c->tmo))
evtimer_del(&c->tmo);
@@ -158,6 +160,9 @@ cleanup_request(struct request *c)
close(c->fd);
free(c->buf);
free(c);
+
+ if (stopping && client_cnt <= 0)
+ sockets_shutdown();
}
static void
@@ -757,6 +762,32 @@ recv_fcgi_pipe(struct gotwebd *env, struct imsg *imsg)
}
static void
+sockets_stop(void)
+{
+ struct socket *sock;
+
+ stopping = 1;
+
+ /*
+ * Deactivate sockets but to do not free them.
+ * Client connections maintain a pointer to them via c->sock.
+ */
+ TAILQ_FOREACH(sock, &gotwebd_env->sockets, entry) {
+ if (sock->fd != -1) {
+ close(sock->fd);
+ sock->fd = -1;
+ }
+ if (event_initialized(&sock->ev))
+ event_del(&sock->ev);
+ if (evtimer_initialized(&sock->ev))
+ evtimer_del(&sock->pause);
+ }
+
+ if (client_cnt == 0)
+ sockets_shutdown();
+}
+
+static void
sockets_dispatch_main(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
@@ -804,6 +835,9 @@ sockets_dispatch_main(int fd, short event, void *arg)
case GOTWEBD_IMSG_CTL_START:
sockets_launch(env);
break;
+ case GOTWEBD_IMSG_CTL_STOP:
+ sockets_stop();
+ break;
default:
fatalx("%s: unknown imsg type %d", __func__,
imsg.hdr.type);
@@ -836,8 +870,10 @@ sockets_sighdlr(int sig, short event, void *arg)
break;
case SIGCHLD:
break;
- case SIGINT:
case SIGTERM:
+ sockets_stop();
+ break;
+ case SIGINT:
sockets_shutdown();
break;
default:
@@ -1193,7 +1229,8 @@ sockets_socket_accept(int fd, short event, void *arg)
backoff.tv_usec = 0;
if (event & EV_TIMEOUT) {
- event_add(&sock->ev, NULL);
+ if (!stopping)
+ event_add(&sock->ev, NULL);
return;
}
@@ -1207,7 +1244,8 @@ sockets_socket_accept(int fd, short event, void *arg)
case EINTR:
case EWOULDBLOCK:
case ECONNABORTED:
- event_add(&sock->ev, NULL);
+ if (!stopping)
+ event_add(&sock->ev, NULL);
return;
case EMFILE:
case ENFILE:
@@ -1225,7 +1263,8 @@ sockets_socket_accept(int fd, short event, void *arg)
close(s);
if (c != NULL)
free(c);
- event_add(&sock->ev, NULL);
+ if (!stopping)
+ event_add(&sock->ev, NULL);
return;
}
@@ -1234,7 +1273,8 @@ sockets_socket_accept(int fd, short event, void *arg)
log_warn("%s: calloc", __func__);
close(s);
cgi_inflight--;
- event_add(&sock->ev, NULL);
+ if (!stopping)
+ event_add(&sock->ev, NULL);
return;
}
@@ -1244,7 +1284,8 @@ sockets_socket_accept(int fd, short event, void *arg)
close(s);
cgi_inflight--;
free(c);
- event_add(&sock->ev, NULL);
+ if (!stopping)
+ event_add(&sock->ev, NULL);
return;
}
graceful gotwebd stop