-
Notifications
You must be signed in to change notification settings - Fork 11
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
HTTP: Warning and test fix #943
Conversation
@@ -606,6 +606,8 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { | |||
req.set(http::field::host, "127.0.0.1:8891"); | |||
boost::beast::http::write(s, req); | |||
} | |||
//make sure got to the point http threads had responses queued |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does it matter if the response is queued or not at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This avoids boost::beast::http::status::service_unavailable
on my machine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe after the boost::beast::http::write(s, req)
try doing a s.wait(wait_read)
, that will guarantee that the response is in flight. just a guess though
@@ -606,6 +606,8 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { | |||
req.set(http::field::host, "127.0.0.1:8891"); | |||
boost::beast::http::write(s, req); | |||
} | |||
//make sure got to the point http threads had responses queued | |||
std::this_thread::sleep_for(std::chrono::seconds(5)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why here sleeping 5 seconds but below sleeping 1 second?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the 1s is not for 4mb messages.
//now rip these connections out before the responses are completely sent | ||
connections.clear(); | ||
//send some requests that should work still | ||
send_4mb_requests(8u); | ||
r = drain_http_replies(); | ||
for (const auto& e : r) { | ||
ilog( "response: ${r}, count: ${c}", ("r", std::string(obsolete_reason(e.first)))("c", e.second)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I almost thought the r
in ${r}
was the r
in r = drain_http_replies()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be adding sleeps to tests
@@ -642,13 +644,14 @@ 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)); | |||
//now rip these connections out before the responses are completely sent | |||
connections.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understood your description right, this is the area that is problematic. Between this line and the line below the http plugin needs to have cleaned up all its ownstanding async_writes. Just closing the socket here does indeed send the FIN but the http threads need time to wake up and handle that error on the async_write to then clear out what's in flight.
I wonder if what might work is to shutdown
each connection and then async_read
on each one until getting confirmation the remote side disconnected via an error code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would likely work. I added a check for bytes_in_flight
since that is really what we want to test anyway. We want to verify that bytes in flight goes to 0 once connections are closed.
Note:start |
|
||
//8 requests to start with | ||
send_requests(8u); | ||
std::unordered_map<boost::beast::http::status, size_t> r = scan_http_replies(); | ||
BOOST_REQUIRE_EQUAL(r[boost::beast::http::status::ok], 8u); | ||
connections.clear(); | ||
wait_for_no_bytes_in_flight(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this test case has to do with requests in flight, not bytes, so this feels mismatched but maybe it still serves enough of its purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A requests in flight would be better and useful to verify in both cases. I'll add it.
@@ -604,6 +604,7 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { | |||
boost::beast::http::request<boost::beast::http::empty_body> req(boost::beast::http::verb::get, "/4megabyte", 11); | |||
req.keep_alive(true); | |||
req.set(http::field::host, "127.0.0.1:8891"); | |||
s.wait(boost::asio::ip::tcp::socket::wait_write); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this and the wait_read
below? Why would the socket not be writable here? And if it isn't writable why does it matter before a sync write is issued?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed. I'll remove.
@@ -622,6 +622,12 @@ 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<uint16_t>::max()) { | |||
while (http_plugin->bytes_in_flight() > 0 && http_plugin->requests_in_flight() > 0 && --max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When waiting for no bytes in flight why do we need to look at requests in flight too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No "need", just thought it was good to also verify requests_in_flight
appropriately hits 0.
@@ -646,9 +652,13 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { | |||
std::this_thread::sleep_for(std::chrono::seconds(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get rid of this final sleep? It seems like waiting for each connection to indicate it's readable would suffice. But if we need to make another busy loop maybe we could wait to see requests_in_flight is 32
@@ -623,7 +623,7 @@ BOOST_FIXTURE_TEST_CASE(bytes_in_flight, http_plugin_test_fixture) { | |||
}; | |||
|
|||
auto wait_for_no_bytes_in_flight = [&](uint16_t max = std::numeric_limits<uint16_t>::max()) { | |||
while (http_plugin->bytes_in_flight() > 0 && http_plugin->requests_in_flight() > 0 && --max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this shouldn't make a difference as they should either both be 0 or both non-zero.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused by that too. And I don't understand the discrepancy why wait_for_no_bytes_in_flight
looks at both while wait_for_no_requests_in_flight
looks at only one. If the intent is to look at both then a common wait_for_nothing_in_flight
could be made that looks at both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In practice the requests in flight also matter. The issue is that bytes in flight can reach 0 before all the requests are done (or started).
bytes_in_flight
is only incremented on sending the response. We do not, currently at least, include the request.
spring/plugins/http_plugin/include/eosio/http_plugin/beast_http_session.hpp
Lines 466 to 468 in 2b43faf
virtual void send_response(std::string&& json, unsigned int code) final { | |
auto payload_size = json.size(); | |
increment_bytes_in_flight(payload_size); |
Therefore, requests can be in progress, but bytes_in_flight
can be 0. So we need to wait until all requests are complete to know that all bytes_in_flight
are accounted for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So could we just wait for requests_in_flight()
to be 0, and then assert that bytes_in_flight()
is 0 as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that sounds better
…th a comment on why
this
not used by lambdaResolves #683