Skip to content

Commit a0843b3

Browse files
committed
Merge pull request #550 from gaudryc/fix_webserver_graceful_stop
Fix webserver graceful stop
2 parents 97c5a82 + c8da7e1 commit a0843b3

File tree

4 files changed

+34
-19
lines changed

4 files changed

+34
-19
lines changed

webserver/cWebem.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,8 @@ void cWebem::Stop() {
9898
_log.Log(LOG_ERROR, "[web:%s] exception thrown while stopping session cleaner", GetPort().c_str());
9999
}
100100
// Stop Web server
101-
if ((myServer != NULL) && !myServer->stopped()) {
102-
myServer->stop(); // asynchronous stop
103-
while(true) {
104-
if (myServer->stopped()) {
105-
break;
106-
}
107-
sleep_milliseconds(500);
108-
}
101+
if (myServer != NULL) {
102+
myServer->stop();
109103
}
110104
}
111105

webserver/connection.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ void connection::start()
119119

120120
void connection::stop()
121121
{
122+
// Timers should be cancelled before stopping to remove tasks from the io_service.
123+
// The io_service will stop naturally when every tasks are removed.
124+
// If timers are not cancelled, the exception ERROR_ABANDONED_WAIT_0 is thrown up to the io_service::run() caller.
122125
cancel_abandoned_timeout();
123126
cancel_read_timeout();
124127

@@ -384,7 +387,7 @@ void connection::stop_gracefully() {
384387
(status_ == WAITING_READ) ||
385388
(status_ == WAITING_HANDSHAKE)) {
386389
// avoid to wait until timeout
387-
connection_manager_.stop(shared_from_this());
390+
stop(); // stop with clearing, it will be done in connection_manager::stop
388391
}
389392
}
390393

webserver/server.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include "server.hpp"
88
#include <fstream>
99
#include "../main/Logger.h"
10+
#include "../main/Helper.h"
11+
#include "../main/localtime_r.h"
1012

1113
namespace http {
1214
namespace server {
@@ -18,7 +20,8 @@ server_base::server_base(const server_settings & settings, request_handler & use
1820
settings_(settings),
1921
request_handler_(user_request_handler),
2022
timeout_(20), // default read timeout in seconds
21-
is_running(false) {
23+
is_running(false),
24+
is_stop_complete(false) {
2225
if (!settings.is_enabled()) {
2326
throw std::invalid_argument("cannot initialize a disabled server (listening port cannot be empty or 0)");
2427
}
@@ -75,13 +78,27 @@ void server_base::run() {
7578

7679
/// Ask the server to stop using asynchronous command
7780
void server_base::stop() {
78-
// Post a call to the stop function so that server_base::stop() is safe to call from any thread.
79-
io_service_.post(boost::bind(&server_base::handle_stop, this));
80-
}
81+
if (is_running) {
82+
// Post a call to the stop function so that server_base::stop() is safe to call from any thread.
83+
io_service_.post(boost::bind(&server_base::handle_stop, this));
84+
} else {
85+
// if io_service is not running then the post call will not be performed
86+
handle_stop();
87+
}
8188

82-
/// Returns true if the server is stopped.
83-
bool server_base::stopped() {
84-
return !is_running;
89+
// Wait for acceptor and connections to stop
90+
int timeout = 15; // force stop after 15 seconds
91+
time_t start = mytime(NULL);
92+
while(true) {
93+
if (!is_running && is_stop_complete) {
94+
break;
95+
}
96+
if ((mytime(NULL) - start) > timeout) {
97+
// timeout occurred
98+
break;
99+
}
100+
sleep_milliseconds(500);
101+
}
85102
}
86103

87104
void server_base::handle_stop() {
@@ -92,6 +109,7 @@ void server_base::handle_stop() {
92109
_log.Log(LOG_ERROR, "[web:%s] exception occurred while closing acceptor", settings_.listening_port.c_str());
93110
}
94111
connection_manager_.stop_all(false);
112+
is_stop_complete = true;
95113
}
96114

97115
server::server(const server_settings & settings, request_handler & user_request_handler) :

webserver/server.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ class server_base : private boost::noncopyable {
3333
/// Stop the server.
3434
void stop();
3535

36-
/// Check if the server is running
37-
bool stopped();
38-
3936
/// Print server settings to string (debug purpose)
4037
virtual std::string to_string() const {
4138
return "'server_base[" + settings_.to_string() + "]'";
@@ -65,6 +62,9 @@ class server_base : private boost::noncopyable {
6562
/// indicate if the server is running
6663
bool is_running;
6764

65+
/// indicate if the server is stopped (acceptor and connections)
66+
bool is_stop_complete;
67+
6868
private:
6969
/// Handle a request to stop the server.
7070
void handle_stop();

0 commit comments

Comments
 (0)