Implement shutdown

This commit is contained in:
Přemysl Eric Janouch 2015-04-10 02:44:13 +02:00
parent 1944f9f17d
commit 6785d3a9ed

View File

@ -1152,6 +1152,7 @@ struct server_context
{
ev_signal sigterm_watcher; ///< Got SIGTERM
ev_signal sigint_watcher; ///< Got SIGINT
ev_timer quit_timeout_watcher; ///< Quit timeout watcher
bool quitting; ///< User requested quitting
struct listener *listeners; ///< Listeners
@ -1164,6 +1165,11 @@ struct server_context
struct str_map config; ///< Server configuration
};
static void initiate_quit (struct server_context *self);
static void try_finish_quit (struct server_context *self);
static void on_quit_timeout (EV_P_ ev_watcher *watcher, int revents);
static void close_listeners (struct server_context *self);
static void
server_context_init (struct server_context *self)
{
@ -1171,10 +1177,10 @@ server_context_init (struct server_context *self)
str_map_init (&self->config);
load_config_defaults (&self->config, g_config_table);
ev_timer_init (&self->quit_timeout_watcher, on_quit_timeout, 0., 0.);
self->quit_timeout_watcher.data = self;
}
static void close_listeners (struct server_context *self);
static void
server_context_free (struct server_context *self)
{
@ -1761,14 +1767,8 @@ struct client_impl
/// Initialize the client as needed
void (*init) (struct client *client);
// TODO: a method for graceful shutdown which will, in the case of
// WebSockets, actually send a "shutdown" close packet, and in the case
// of FastCGI will FCGI_END_REQUEST everything with FCGI_REQUEST_COMPLETE
// and FCGI_OVERLOADED all incoming requests in the meantime (the FastCGI
// specification isn't very clear about how we should respond to this).
//
// We then should set up a timer for about a second until we kill all
// clients for good.
/// Attempt a graceful shutdown
void (*shutdown) (struct client *client);
/// Do any additional cleanup
void (*destroy) (struct client *client);
@ -1817,6 +1817,8 @@ client_remove (struct client *client)
xclose (client->socket_fd);
client_free (client);
free (client);
try_finish_quit (ctx);
}
// - - FastCGI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1907,6 +1909,16 @@ client_fcgi_init (struct client *client)
self->muxer.user_data = client;
}
static void
client_fcgi_shutdown (struct client *client)
{
struct client_fcgi *self = client->impl_data;
// TODO: respond with FCGI_END_REQUEST: FCGI_REQUEST_COMPLETE to everything,
// and start sending out FCGI_OVERLOADED to all incoming requests. The
// FastCGI specification isn't very clear about what we should do.
}
static void
client_fcgi_destroy (struct client *client)
{
@ -1927,9 +1939,10 @@ client_fcgi_push (struct client *client, const void *data, size_t len)
static struct client_impl g_client_fcgi =
{
.init = client_fcgi_init,
.destroy = client_fcgi_destroy,
.push = client_fcgi_push,
.init = client_fcgi_init,
.shutdown = client_fcgi_shutdown,
.destroy = client_fcgi_destroy,
.push = client_fcgi_push,
};
// - - SCGI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2086,6 +2099,13 @@ client_ws_init (struct client *client)
self->handler.max_payload_len = 1 << 10;
}
static void
client_ws_shutdown (struct client *client)
{
struct client_ws *self = client->impl_data;
ws_handler_close (&self->handler, WS_STATUS_GOING_AWAY, NULL, 0);
}
static void
client_ws_destroy (struct client *client)
{
@ -2105,12 +2125,12 @@ client_ws_push (struct client *client, const void *data, size_t len)
static struct client_impl g_client_ws =
{
.init = client_ws_init,
.destroy = client_ws_destroy,
.push = client_ws_push,
.init = client_ws_init,
.shutdown = client_ws_shutdown,
.destroy = client_ws_destroy,
.push = client_ws_push,
};
// --- Basic server stuff ------------------------------------------------------
struct listener
@ -2123,7 +2143,6 @@ struct listener
static void
close_listeners (struct server_context *self)
{
// TODO: factor out the closing act, to be used in initiate_quit()
for (size_t i = 0; i < self->n_listeners; i++)
{
struct listener *listener = &self->listeners[i];
@ -2136,6 +2155,39 @@ close_listeners (struct server_context *self)
}
}
static void
try_finish_quit (struct server_context *self)
{
if (!self->quitting || self->clients)
return;
ev_timer_stop (EV_DEFAULT_ &self->quit_timeout_watcher);
ev_break (EV_DEFAULT_ EVBREAK_ALL);
}
static void
on_quit_timeout (EV_P_ ev_watcher *watcher, int revents)
{
struct server_context *self = watcher->data;
(void) loop;
(void) revents;
LIST_FOR_EACH (struct client, iter, self->clients)
client_remove (iter);
}
static void
initiate_quit (struct server_context *self)
{
close_listeners (self);
LIST_FOR_EACH (struct client, iter, self->clients)
if (iter->impl->shutdown)
iter->impl->shutdown (iter->impl_data);
ev_timer_set (&self->quit_timeout_watcher, 3., 0.);
self->quitting = true;
}
static bool
client_read_loop (EV_P_ struct client *client, ev_io *watcher)
{
@ -2217,6 +2269,7 @@ make_client (EV_P_ struct client_impl *impl, int sock_fd)
static void
on_client_available (EV_P_ ev_io *watcher, int revents)
{
struct server_context *ctx = ev_userdata (loop);
struct listener *listener = watcher->data;
(void) revents;
@ -2235,7 +2288,7 @@ on_client_available (EV_P_ ev_io *watcher, int revents)
ev_io_stop (EV_A_ watcher);
print_fatal ("%s: %s", "accept", strerror (errno));
// TODO: initiate_quit (ctx);
initiate_quit (ctx);
}
// --- Application setup -------------------------------------------------------