diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index 6e66aa95bc..a3f790247d 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -613,7 +613,7 @@ namespace eosio { // returns true if `category` is enabled in http_plugin bool http_plugin::is_enabled(api_category category) const { return std::any_of(my->categories_by_address.begin(), my->categories_by_address.end(), - [&category, this](const auto& entry) { + [&category](const auto& entry) { const auto& [address, categories] = entry; return categories.contains(category); }); @@ -635,6 +635,14 @@ namespace eosio { my->plugin_state->update_metrics = std::move(fun); } + size_t http_plugin::requests_in_flight() const { + return my->plugin_state->requests_in_flight; + } + + size_t http_plugin::bytes_in_flight() const { + return my->plugin_state->bytes_in_flight; + } + std::atomic& http_plugin::listening() { return my->listening; } diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index e4139730b4..5533aba41f 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -133,6 +133,10 @@ namespace eosio { void register_update_metrics(std::function&& fun); + size_t requests_in_flight() const; + + size_t bytes_in_flight() const; + std::atomic& listening(); private: std::shared_ptr my; diff --git a/plugins/http_plugin/tests/unit_tests.cpp b/plugins/http_plugin/tests/unit_tests.cpp index 49b37eb0eb..145f21f823 100644 --- a/plugins/http_plugin/tests/unit_tests.cpp +++ b/plugins/http_plugin/tests/unit_tests.cpp @@ -622,6 +622,18 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { return count_of_status_replies; }; + auto wait_for_no_bytes_in_flight = [&](uint16_t max = std::numeric_limits::max()) { + while ((http_plugin->bytes_in_flight() > 0 || http_plugin->requests_in_flight() > 0) && --max) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + BOOST_CHECK(max > 0); + }; + + auto wait_for_requests = [&](uint16_t num_requests, uint16_t max = std::numeric_limits::max()) { + while (http_plugin->requests_in_flight() < num_requests && --max) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + BOOST_CHECK(max > 0); + }; + //send a single request to start with send_4mb_requests(1u); @@ -643,12 +655,16 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { //load up some more requests that exceed max send_4mb_requests(32u); //make sure got to the point http threads had responses queued - std::this_thread::sleep_for(std::chrono::seconds(1)); + wait_for_requests(32u); //now rip these connections out before the responses are completely sent connections.clear(); + wait_for_no_bytes_in_flight(); //send some requests that should work still send_4mb_requests(8u); r = drain_http_replies(); + for (const auto& e : r) { + ilog( "response: ${f}, count: ${c}", ("f", std::string(obsolete_reason(e.first)))("c", e.second)); + } BOOST_REQUIRE_EQUAL(r[boost::beast::http::status::ok], 8u); } @@ -694,12 +710,19 @@ BOOST_FIXTURE_TEST_CASE(requests_in_flight, http_plugin_test_fixture) { return count_of_status_replies; }; + auto wait_for_no_requests_in_flight = [&](uint16_t max = std::numeric_limits::max()) { + while (http_plugin->requests_in_flight() > 0 && --max) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + BOOST_CHECK(max > 0); + }; + //8 requests to start with send_requests(8u); std::unordered_map r = scan_http_replies(); BOOST_REQUIRE_EQUAL(r[boost::beast::http::status::ok], 8u); connections.clear(); + wait_for_no_requests_in_flight(); //24 requests will exceed threshold send_requests(24u); @@ -708,12 +731,17 @@ BOOST_FIXTURE_TEST_CASE(requests_in_flight, http_plugin_test_fixture) { BOOST_REQUIRE_GT(r[boost::beast::http::status::service_unavailable], 0u); BOOST_REQUIRE_EQUAL(r[boost::beast::http::status::service_unavailable] + r[boost::beast::http::status::ok], 24u); connections.clear(); + wait_for_no_requests_in_flight(); //requests should still work send_requests(8u); r = scan_http_replies(); + for (const auto& e : r) { + ilog( "response: ${f}, count: ${c}", ("f", std::string(obsolete_reason(e.first)))("c", e.second)); + } BOOST_REQUIRE_EQUAL(r[boost::beast::http::status::ok], 8u); connections.clear(); + wait_for_no_requests_in_flight(); } //A warning for future tests: destruction of http_plugin_test_fixture sometimes does not destroy http_plugin's listeners. Tests