Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added wait timeout to server start #918

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions include/crow/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ namespace crow
}

/// \brief Get the number of threads that server is using
std::uint16_t concurrency()
std::uint16_t concurrency() const
{
return concurrency_;
}
Expand Down Expand Up @@ -514,11 +514,18 @@ namespace crow
#endif
validate();

error_code ec;
asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
if (ec){
CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
return;
}
tcp::endpoint endpoint(addr, port_);
#ifdef CROW_ENABLE_SSL
if (ssl_used_)
{
router_.using_ssl = true;
ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
ssl_server_->set_tick_function(tick_interval_, tick_function_);
ssl_server_->signal_clear();
for (auto snum : signals_)
Expand All @@ -531,7 +538,7 @@ namespace crow
else
#endif
{
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
server_->set_tick_function(tick_interval_, tick_function_);
for (auto snum : signals_)
{
Expand Down Expand Up @@ -703,19 +710,32 @@ namespace crow
}

/// \brief Wait until the server has properly started
void wait_for_server_start()
std::cv_status wait_for_server_start(std::chrono::milliseconds wait_timeout = std::chrono::milliseconds(3000))
{
std::cv_status status = std::cv_status::no_timeout;
auto wait_until = std::chrono::steady_clock::now() + wait_timeout;
{
std::unique_lock<std::mutex> lock(start_mutex_);
while (!server_started_)
cv_started_.wait(lock);
while (!server_started_ && (status == std::cv_status::no_timeout))
{
status = cv_started_.wait_until(lock, wait_until);
}
}
if (server_)
server_->wait_for_start();

if (status == std::cv_status::no_timeout)
{
if (server_)
{
status = server_->wait_for_start(wait_until);
}
#ifdef CROW_ENABLE_SSL
else if (ssl_server_)
ssl_server_->wait_for_start();
else if (ssl_server_)
{
status = ssl_server_->wait_for_start(wait_until);
}
#endif
}
return status;
}

private:
Expand Down
28 changes: 14 additions & 14 deletions include/crow/http_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@ namespace crow // NOTE: Already documented in "crow/app.h"
class Server
{
public:
Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr):
acceptor_(io_service_, tcp::endpoint(asio::ip::address::from_string(bindaddr), port)),
Server(Handler* handler, const tcp::endpoint& endpoint, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr):
acceptor_(io_service_, endpoint),
signals_(io_service_),
tick_timer_(io_service_),
handler_(handler),
concurrency_(concurrency),
timeout_(timeout),
server_name_(server_name),
port_(port),
bindaddr_(bindaddr),
task_queue_length_pool_(concurrency_ - 1),
middlewares_(middlewares),
adaptor_ctx_(adaptor_ctx)
Expand Down Expand Up @@ -150,11 +148,12 @@ namespace crow // NOTE: Already documented in "crow/app.h"
});
}

port_ = acceptor_.local_endpoint().port();
handler_->port(port_);
handler_->port(acceptor_.local_endpoint().port());


CROW_LOG_INFO << server_name_ << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") << bindaddr_ << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads";
CROW_LOG_INFO << server_name_
<< " server is running at " << (handler_->ssl_used() ? "https://" : "http://")
<< acceptor_.local_endpoint().address() << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads";
CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs.";

signals_.async_wait(
Expand Down Expand Up @@ -192,16 +191,19 @@ namespace crow // NOTE: Already documented in "crow/app.h"
io_service_.stop(); // Close main io_service
}

uint16_t port(){
uint16_t port() const {
return acceptor_.local_endpoint().port();
}

/// Wait until the server has properly started
void wait_for_start()
/// Wait until the server has properly started or until timeout
std::cv_status wait_for_start(std::chrono::steady_clock::time_point wait_until)
{
std::unique_lock<std::mutex> lock(start_mutex_);
while (!server_started_)
cv_started_.wait(lock);

std::cv_status status = std::cv_status::no_timeout;
while (!server_started_ && ( status==std::cv_status::no_timeout ))
status = cv_started_.wait_until(lock,wait_until);
return status;
}

void signal_clear()
Expand Down Expand Up @@ -290,8 +292,6 @@ namespace crow // NOTE: Already documented in "crow/app.h"
uint16_t concurrency_{2};
std::uint8_t timeout_;
std::string server_name_;
uint16_t port_;
std::string bindaddr_;
std::vector<std::atomic<unsigned int>> task_queue_length_pool_;

std::chrono::milliseconds tick_interval_;
Expand Down
24 changes: 20 additions & 4 deletions tests/unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include <type_traits>
#include <regex>

Expand Down Expand Up @@ -603,7 +602,22 @@ TEST_CASE("server_handling_error_request")
app.stop();
} // server_handling_error_request

TEST_CASE("server_dynamic_port_allication")
TEST_CASE("server_invalid_ip_address")
{
SimpleApp app;
CROW_ROUTE(app, "/")
([] {
return "A";
});
auto _ = app.bindaddr("192.").port(45451).run_async();
auto state = app.wait_for_server_start();

// we should run into a timeout as the server will not started
CHECK(state==cv_status::timeout);
} // server_invalid_ip_address


TEST_CASE("server_dynamic_port_allocation")
{
SimpleApp app;
CROW_ROUTE(app, "/")
Expand All @@ -619,7 +633,7 @@ TEST_CASE("server_dynamic_port_allication")
asio::ip::address::from_string(LOCALHOST_ADDRESS), app.port()));
}
app.stop();
} // server_dynamic_port_allication
} // server_dynamic_port_allocation

TEST_CASE("server_handling_error_request_http_version")
{
Expand Down Expand Up @@ -1498,7 +1512,9 @@ struct NullSimpleMiddleware
TEST_CASE("middleware_simple")
{
App<NullMiddleware, NullSimpleMiddleware> app;
decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
asio::ip::address adr = asio::ip::make_address(LOCALHOST_ADDRESS);
tcp::endpoint ep(adr,45451);
decltype(app)::server_t server(&app, ep);
CROW_ROUTE(app, "/")
([&](const crow::request& req) {
app.get_context<NullMiddleware>(req);
Expand Down
Loading