From 390239c51b6ecef92af62e0ea436fb5ce8a995fd Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sat, 19 Feb 2022 13:31:39 +0300 Subject: [PATCH] Don't terminate HTTP requests with timeouts if response is already available in the socket --- src/http_client.cpp | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/http_client.cpp b/src/http_client.cpp index d8641892..e96bfe50 100644 --- a/src/http_client.cpp +++ b/src/http_client.cpp @@ -65,7 +65,7 @@ struct http_co_t void next_request(); void handle_events(); void handle_connect_result(); - void submit_read(); + void submit_read(bool check_timeout); void submit_send(); bool handle_read(); void post_message(int type, const std::string & msg); @@ -167,10 +167,19 @@ void http_co_t::send_request(const std::string & host, const std::string & reque timeout_id = tfd->set_timer(request_timeout, false, [this](int timer_id) { stackin(); - close_connection(); - parsed = { .error = "HTTP request timed out" }; - run_cb_and_clear(); - next_request(); + if (state == HTTP_CO_REQUEST_SENT) + { + // In case of high CPU load, we may not handle etcd responses in time + // For this case, first check the socket and only then terminate request with the timeout + submit_read(true); + } + else + { + close_connection(); + parsed = { .error = "HTTP request timed out" }; + run_cb_and_clear(); + next_request(); + } stackout(); }); } @@ -328,7 +337,7 @@ void http_co_t::handle_events() epoll_events &= ~EPOLLOUT; if (epoll_events & EPOLLIN) { - submit_read(); + submit_read(false); } else if (epoll_events & (EPOLLRDHUP|EPOLLERR)) { @@ -418,10 +427,11 @@ again: stackout(); } -void http_co_t::submit_read() +void http_co_t::submit_read(bool check_timeout) { stackin(); int res; +again: if (rbuf.size() != READ_BUFFER_SIZE) { rbuf.resize(READ_BUFFER_SIZE); @@ -436,7 +446,23 @@ void http_co_t::submit_read() } if (res == -EAGAIN || res == -EINTR) { - epoll_events = epoll_events & ~EPOLLIN; + if (check_timeout) + { + if (res == -EINTR) + goto again; + else + { + // Timeout happened and there is no data to read + close_connection(); + parsed = { .error = "HTTP request timed out" }; + run_cb_and_clear(); + next_request(); + } + } + else + { + epoll_events = epoll_events & ~EPOLLIN; + } } else if (res <= 0) {