From 45d2969dcbf5bcc9d2354a52a3611cd79acc77b6 Mon Sep 17 00:00:00 2001 From: An Tao Date: Sat, 21 Mar 2020 21:29:33 +0800 Subject: [PATCH] Graceful shutdown (#393) Call app().quit() to gracefully stop a drogon application. --- examples/simple_example/api_v1_ApiTest.h | 7 +++++ lib/src/HttpAppFrameworkImpl.cc | 5 +++- lib/src/HttpServer.cc | 5 +++- lib/src/HttpServer.h | 1 + lib/src/ListenerManager.cc | 38 +++++++++++++++--------- lib/src/ListenerManager.h | 2 ++ trantor | 2 +- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/examples/simple_example/api_v1_ApiTest.h b/examples/simple_example/api_v1_ApiTest.h index a921e255..867d386f 100644 --- a/examples/simple_example/api_v1_ApiTest.h +++ b/examples/simple_example/api_v1_ApiTest.h @@ -31,6 +31,8 @@ class ApiTest : public drogon::HttpController ADD_METHOD_TO(ApiTest::get2, "/absolute/{}", Get); // path is /absolute/{arg1} + ADD_METHOD_TO(ApiTest::shutdown, "/shutdown", + Get); // path is /shutdown METHOD_ADD(ApiTest::jsonTest, "/json", Post); METHOD_ADD(ApiTest::formTest, "/form", Post); METHOD_ADD(ApiTest::attributesTest, "/attrs", Get); @@ -66,6 +68,11 @@ class ApiTest : public drogon::HttpController std::function &&callback, int p1, std::string &&p2); + void shutdown(const HttpRequestPtr &req, + std::function &&callback) + { + app().quit(); + } public: ApiTest() diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 3cd4f37a..e35ab713 100644 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -885,7 +885,10 @@ void HttpAppFrameworkImpl::quit() { if (getLoop()->isRunning()) { - getLoop()->queueInLoop([this]() { getLoop()->quit(); }); + getLoop()->queueInLoop([this]() { + listenerManagerPtr_->stopListening(); + getLoop()->quit(); + }); } } diff --git a/lib/src/HttpServer.cc b/lib/src/HttpServer.cc index 2cda5d3e..60bec4f4 100644 --- a/lib/src/HttpServer.cc +++ b/lib/src/HttpServer.cc @@ -139,7 +139,10 @@ void HttpServer::start() << server_.ipPort(); server_.start(); } - +void HttpServer::stop() +{ + server_.stop(); +} void HttpServer::onConnection(const TcpConnectionPtr &conn) { if (conn->connected()) diff --git a/lib/src/HttpServer.h b/lib/src/HttpServer.h index 853d106f..f64f182c 100644 --- a/lib/src/HttpServer.h +++ b/lib/src/HttpServer.h @@ -75,6 +75,7 @@ class HttpServer : trantor::NonCopyable return server_.getIoLoops(); } void start(); + void stop(); void enableSSL(const std::string &certPath, const std::string &keyPath) { diff --git a/lib/src/ListenerManager.cc b/lib/src/ListenerManager.cc index bf84078e..deef5da7 100644 --- a/lib/src/ListenerManager.cc +++ b/lib/src/ListenerManager.cc @@ -79,13 +79,12 @@ std::vector ListenerManager::createListeners( &syncAdvices) { #ifdef __linux__ - std::vector ioLoops; for (size_t i = 0; i < threadNum; ++i) { LOG_TRACE << "thread num=" << threadNum; auto loopThreadPtr = std::make_shared("DrogonIoLoop"); listeningloopThreads_.push_back(loopThreadPtr); - ioLoops.push_back(loopThreadPtr->getLoop()); + ioLoops_.push_back(loopThreadPtr->getLoop()); for (auto const &listener : listeners_) { auto const &ip = listener.ip_; @@ -183,9 +182,9 @@ std::vector ListenerManager::createListeners( serverPtr->start(); servers_.push_back(serverPtr); } - auto ioLoops = ioLoopThreadPoolPtr_->getLoops(); + ioLoops_ = ioLoopThreadPoolPtr_->getLoops(); #endif - return ioLoops; + return ioLoops_; } void ListenerManager::startListening() @@ -200,16 +199,6 @@ void ListenerManager::startListening() ListenerManager::~ListenerManager() { - for (size_t i = 0; i < servers_.size(); ++i) - { - std::promise pro; - auto f = pro.get_future(); - servers_[i]->getLoop()->runInLoop([&pro, this, i] { - servers_[i].reset(); - pro.set_value(1); - }); - (void)f.get(); - } } trantor::EventLoop *ListenerManager::getIOLoop(size_t id) const @@ -235,3 +224,24 @@ trantor::EventLoop *ListenerManager::getIOLoop(size_t id) const return ioLoopThreadPoolPtr_->getLoop(id); #endif } +void ListenerManager::stopListening() +{ + for (auto &serverPtr : servers_) + { + serverPtr->stop(); + } + for (auto loop : ioLoops_) + { + assert(!loop->isInLoopThread()); + if (loop->isRunning()) + { + std::promise pro; + auto f = pro.get_future(); + loop->queueInLoop([loop, &pro]() { + loop->quit(); + pro.set_value(1); + }); + (void)f.get(); + } + } +} diff --git a/lib/src/ListenerManager.h b/lib/src/ListenerManager.h index e737bd15..9119ec1e 100644 --- a/lib/src/ListenerManager.h +++ b/lib/src/ListenerManager.h @@ -47,6 +47,8 @@ class ListenerManager : public trantor::NonCopyable ~ListenerManager(); trantor::EventLoop *getIOLoop(size_t id) const; + void stopListening(); + std::vector ioLoops_; private: struct ListenerInfo diff --git a/trantor b/trantor index f38eba77..0415747a 160000 --- a/trantor +++ b/trantor @@ -1 +1 @@ -Subproject commit f38eba777fa91d3bc2443efe853fcb8b64afa459 +Subproject commit 0415747a7e2bbf1950d924544ff7855b1ad8da6f