diff --git a/library/common/engine.cc b/library/common/engine.cc index 509d7e6c69..49561991bf 100644 --- a/library/common/engine.cc +++ b/library/common/engine.cc @@ -255,4 +255,10 @@ void Engine::flushStats() { server_->flushStats(); } +void Engine::drainConnections() { + ASSERT(dispatcher_->isThreadSafe(), + "drainConnections must be called from the dispatcher's context"); + server_->clusterManager().drainConnections(); +} + } // namespace Envoy diff --git a/library/common/engine.h b/library/common/engine.h index 6598c22091..a7201325b2 100644 --- a/library/common/engine.h +++ b/library/common/engine.h @@ -107,6 +107,11 @@ class Engine : public Logger::Loggable { */ void flushStats(); + /** + * Drain all upstream connections associated with this Engine. + */ + void drainConnections(); + private: envoy_status_t main(std::string config, std::string log_level); diff --git a/library/common/main_interface.cc b/library/common/main_interface.cc index 4fd760c07d..3a4259c8a3 100644 --- a/library/common/main_interface.cc +++ b/library/common/main_interface.cc @@ -185,7 +185,6 @@ envoy_engine_t init_engine(envoy_engine_callbacks callbacks, envoy_logger logger envoy_status_t run_engine(envoy_engine_t, const char* config, const char* log_level) { // This will change once multiple engine support is in place. // https://github.com/lyft/envoy-mobile/issues/332 - if (auto e = engine()) { e->run(config, log_level); return ENVOY_SUCCESS; @@ -200,3 +199,17 @@ void terminate_engine(envoy_engine_t) { strong_engine_.reset(); e->terminate(); } + +envoy_status_t drain_connections(envoy_engine_t) { + // This will change once multiple engine support is in place. + // https://github.com/lyft/envoy-mobile/issues/332 + if (auto e = engine()) { + e->dispatcher().post([]() { + if (auto e = engine()) { + e->drainConnections(); + } + }); + return ENVOY_SUCCESS; + } + return ENVOY_FAILURE; +} diff --git a/library/common/main_interface.h b/library/common/main_interface.h index e7297f379e..54a9293b6a 100644 --- a/library/common/main_interface.h +++ b/library/common/main_interface.h @@ -185,6 +185,13 @@ envoy_status_t run_engine(envoy_engine_t engine, const char* config, const char* */ void terminate_engine(envoy_engine_t engine); +/** + * Drain all upstream connections associated with an engine + * @param engine, handle to the engine to drain. + * @return envoy_status_t, the resulting status of the operation. + */ +envoy_status_t drain_connections(envoy_engine_t engine); + #ifdef __cplusplus } // functions #endif diff --git a/test/common/main_interface_test.cc b/test/common/main_interface_test.cc index e430e7f50b..33930c6c14 100644 --- a/test/common/main_interface_test.cc +++ b/test/common/main_interface_test.cc @@ -626,4 +626,26 @@ TEST(EngineTest, EventTrackerRegistersAssertionFailureRecordAction) { ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); } +TEST(MainInterfaceTest, DrainConnections) { + engine_test_context test_context{}; + envoy_engine_callbacks engine_cbs{[](void* context) -> void { + auto* engine_running = + static_cast(context); + engine_running->on_engine_running.Notify(); + } /*on_engine_running*/, + [](void* context) -> void { + auto* exit = static_cast(context); + exit->on_exit.Notify(); + } /*on_exit*/, + &test_context /*context*/}; + envoy_engine_t engine_handle = init_engine(engine_cbs, {}, {}); + run_engine(engine_handle, MINIMAL_TEST_CONFIG.c_str(), LEVEL_DEBUG.c_str()); + ASSERT_TRUE(test_context.on_engine_running.WaitForNotificationWithTimeout(absl::Seconds(3))); + + ASSERT_EQ(ENVOY_SUCCESS, drain_connections(engine_handle)); + + terminate_engine(engine_handle); + ASSERT_TRUE(test_context.on_exit.WaitForNotificationWithTimeout(absl::Seconds(3))); +} + } // namespace Envoy