]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: server: Implemented means to gracefully shut down the server.
authorStephan Bosch <stephan@dovecot.fi>
Sat, 16 Apr 2016 01:54:00 +0000 (03:54 +0200)
committerGitLab <gitlab@git.dovecot.net>
Fri, 29 Apr 2016 19:29:28 +0000 (22:29 +0300)
While shutting down, it will not accept new requests and connections are closed once they become idle.

src/lib-http/http-server-connection.c
src/lib-http/http-server-private.h
src/lib-http/http-server.c
src/lib-http/http-server.h

index 94713e6805b41004257c8f06327206cadd484b1d..6e166817e3ac03da611c5612d7aa1e25725db77d 100644 (file)
@@ -151,6 +151,16 @@ http_server_connection_timeout_reset(struct http_server_connection *conn)
                timeout_reset(conn->to_idle);
 }
 
+bool http_server_connection_shut_down(struct http_server_connection *conn)
+{
+       if (conn->request_queue_head == NULL ||
+               conn->request_queue_head->state == HTTP_SERVER_REQUEST_STATE_NEW) {
+               http_server_connection_close(&conn, "Server shutting down");
+               return TRUE;
+       }
+       return FALSE;
+}
+
 static void http_server_connection_ready(struct http_server_connection *conn)
 {
        struct stat st;
@@ -403,17 +413,24 @@ static bool
 http_server_connection_pipeline_is_full(struct http_server_connection *conn)
 {
        return (conn->request_queue_count >=
-                       conn->server->set.max_pipelined_requests);
+                       conn->server->set.max_pipelined_requests ||
+                       conn->server->shutting_down);
 }
 
 static void
 http_server_connection_pipeline_handle_full(
        struct http_server_connection *conn)
 {
-       http_server_connection_debug(conn,
-               "Pipeline full (%u requests pending; %u maximum)",
-               conn->request_queue_count,
-               conn->server->set.max_pipelined_requests);
+       if (conn->server->shutting_down) {
+               http_server_connection_debug(conn,
+                       "Pipeline full (%u requests pending; server shutting down)",
+                       conn->request_queue_count);
+       } else {
+               http_server_connection_debug(conn,
+                       "Pipeline full (%u requests pending; %u maximum)",
+                       conn->request_queue_count,
+                       conn->server->set.max_pipelined_requests);
+       }
        http_server_connection_input_halt(conn);
 }
 
@@ -517,6 +534,12 @@ static void http_server_connection_input(struct connection *_conn)
        bool cont;
        int ret;
 
+       if (conn->server->shutting_down) {
+               if (!http_server_connection_shut_down(conn))
+                       http_server_connection_pipeline_handle_full(conn);
+               return;
+       }
+
        i_assert(!conn->in_req_callback);
        i_assert(!conn->input_broken && conn->incoming_payload == NULL);
        i_assert(!conn->close_indicated);
@@ -881,7 +904,8 @@ static int http_server_connection_send_responses(
 
        /* accept more requests if possible */
        if (conn->incoming_payload == NULL &&
-               conn->request_queue_count < conn->server->set.max_pipelined_requests) {
+               conn->request_queue_count < conn->server->set.max_pipelined_requests &&
+               !conn->server->shutting_down) {
                http_server_connection_input_resume(conn);
                return 1;
        }
@@ -947,6 +971,10 @@ int http_server_connection_output(struct http_server_connection *conn)
                }
        }
 
+       if (conn->server->shutting_down &&
+               http_server_connection_shut_down(conn))
+               return 1;
+
        if (!http_server_connection_pipeline_is_full(conn)) {
                http_server_connection_input_resume(conn);
                if (pipeline_was_full && conn->conn.io != NULL)
@@ -997,6 +1025,8 @@ http_server_connection_create(struct http_server *server,
        in_port_t port;
        const char *name;
 
+       i_assert(!server->shutting_down);
+
        conn = i_new(struct http_server_connection, 1);
        conn->refcount = 1;
        conn->id = id++;
index 73788bef68c85c6b25b3bf1bc461079c828ef7d9..b0a512898bfeb7da4f611ea0331c101c575e5d3f 100644 (file)
@@ -139,6 +139,8 @@ struct http_server {
        struct ssl_iostream_context *ssl_ctx;
 
        struct connection_list *conn_list;
+
+       unsigned int shutting_down:1;    /* shutting down server */
 };
 
 static inline const char *
@@ -211,6 +213,8 @@ http_server_request_version_equals(struct http_server_request *req,
 
 struct connection_list *http_server_connection_list_init(void);
 
+bool http_server_connection_shut_down(struct http_server_connection *conn);
+
 void http_server_connection_switch_ioloop(struct http_server_connection *conn);
 
 void http_server_connection_write_failed(struct http_server_connection *conn,
index 7f9f28df4fceca3405a7e27dc852f420604e079f..f036d3326f2e4330ddbc512468fbd41e02e9a89f 100644 (file)
@@ -69,3 +69,19 @@ void http_server_switch_ioloop(struct http_server *server)
                http_server_connection_switch_ioloop(conn);
        }
 }
+
+void http_server_shut_down(struct http_server *server)
+{
+       struct connection *_conn, *_next;
+
+       server->shutting_down = TRUE;
+
+       for (_conn = server->conn_list->connections;
+               _conn != NULL; _conn = _next) {
+               struct http_server_connection *conn =
+                       (struct http_server_connection *)_conn;
+
+               _next = _conn->next;
+               (void)http_server_connection_shut_down(conn);
+       }
+}
index b90a39673127917159e0a8af63b32ca10da237c6..53ec3ac521693da294e436c7040d9e1a5e199094 100644 (file)
@@ -68,6 +68,9 @@ typedef void (*http_server_tunnel_callback_t)(void *context,
 
 struct http_server *http_server_init(const struct http_server_settings *set);
 void http_server_deinit(struct http_server **_server);
+/* shut down the server; accept no new requests and drop connections once
+   they become idle */
+void http_server_shut_down(struct http_server *server);
 
 struct http_server_connection *
 http_server_connection_create(struct http_server *server,