nghttpx: Retry h1 backend request if first write fails
This commit is contained in:
parent
e6b4454e48
commit
c4aeadd57d
|
@ -922,6 +922,10 @@ bool Downstream::get_request_pending() const { return request_pending_; }
|
||||||
|
|
||||||
void Downstream::set_request_header_sent(bool f) { request_header_sent_ = f; }
|
void Downstream::set_request_header_sent(bool f) { request_header_sent_ = f; }
|
||||||
|
|
||||||
|
bool Downstream::get_request_header_sent() const {
|
||||||
|
return request_header_sent_;
|
||||||
|
}
|
||||||
|
|
||||||
bool Downstream::request_submission_ready() const {
|
bool Downstream::request_submission_ready() const {
|
||||||
return (request_state_ == Downstream::HEADER_COMPLETE ||
|
return (request_state_ == Downstream::HEADER_COMPLETE ||
|
||||||
request_state_ == Downstream::MSG_COMPLETE) &&
|
request_state_ == Downstream::MSG_COMPLETE) &&
|
||||||
|
|
|
@ -312,6 +312,7 @@ public:
|
||||||
void set_request_pending(bool f);
|
void set_request_pending(bool f);
|
||||||
bool get_request_pending() const;
|
bool get_request_pending() const;
|
||||||
void set_request_header_sent(bool f);
|
void set_request_header_sent(bool f);
|
||||||
|
bool get_request_header_sent() const;
|
||||||
// Returns true if request is ready to be submitted to downstream.
|
// Returns true if request is ready to be submitted to downstream.
|
||||||
// When sending pending request, get_request_pending() should be
|
// When sending pending request, get_request_pending() should be
|
||||||
// checked too because this function may return true when
|
// checked too because this function may return true when
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum ErrorCode {
|
||||||
SHRPX_ERR_EOF = -101,
|
SHRPX_ERR_EOF = -101,
|
||||||
SHRPX_ERR_INPROGRESS = -102,
|
SHRPX_ERR_INPROGRESS = -102,
|
||||||
SHRPX_ERR_DCONN_CANCELED = -103,
|
SHRPX_ERR_DCONN_CANCELED = -103,
|
||||||
|
SHRPX_ERR_RETRY = -104,
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -1212,7 +1212,7 @@ int Http2Upstream::downstream_write(DownstreamConnection *dconn) {
|
||||||
return downstream_error(dconn, Downstream::EVENT_ERROR);
|
return downstream_error(dconn, Downstream::EVENT_ERROR);
|
||||||
}
|
}
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return rv;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,13 +119,33 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||||
|
int rv;
|
||||||
auto conn = static_cast<Connection *>(w->data);
|
auto conn = static_cast<Connection *>(w->data);
|
||||||
auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
|
auto dconn = static_cast<HttpDownstreamConnection *>(conn->data);
|
||||||
auto downstream = dconn->get_downstream();
|
auto downstream = dconn->get_downstream();
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
auto handler = upstream->get_client_handler();
|
auto handler = upstream->get_client_handler();
|
||||||
|
|
||||||
if (upstream->downstream_write(dconn) != 0) {
|
rv = upstream->downstream_write(dconn);
|
||||||
|
if (rv == SHRPX_ERR_RETRY) {
|
||||||
|
downstream->pop_downstream_connection();
|
||||||
|
|
||||||
|
auto ndconn = handler->get_downstream_connection(downstream);
|
||||||
|
if (ndconn) {
|
||||||
|
if (downstream->attach_downstream_connection(std::move(ndconn)) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
downstream->set_request_state(Downstream::CONNECT_FAIL);
|
||||||
|
|
||||||
|
if (upstream->on_downstream_abort_request(downstream, 503) != 0) {
|
||||||
|
delete handler;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
delete handler;
|
delete handler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,7 +198,8 @@ HttpDownstreamConnection::HttpDownstreamConnection(
|
||||||
raddr_(nullptr),
|
raddr_(nullptr),
|
||||||
ioctrl_(&conn_.rlimit),
|
ioctrl_(&conn_.rlimit),
|
||||||
response_htp_{0},
|
response_htp_{0},
|
||||||
initial_addr_idx_(initial_addr_idx) {}
|
initial_addr_idx_(initial_addr_idx),
|
||||||
|
reuse_first_write_done_(true) {}
|
||||||
|
|
||||||
HttpDownstreamConnection::~HttpDownstreamConnection() {
|
HttpDownstreamConnection::~HttpDownstreamConnection() {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
@ -449,6 +470,9 @@ int HttpDownstreamConnection::initiate_connection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ev_set_cb(&conn_.rev, readcb);
|
ev_set_cb(&conn_.rev, readcb);
|
||||||
|
|
||||||
|
do_write_ = &HttpDownstreamConnection::write_reuse_first;
|
||||||
|
reuse_first_write_done_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_parser_init(&response_htp_, HTTP_RESPONSE);
|
http_parser_init(&response_htp_, HTTP_RESPONSE);
|
||||||
|
@ -458,6 +482,10 @@ int HttpDownstreamConnection::initiate_connection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int HttpDownstreamConnection::push_request_headers() {
|
int HttpDownstreamConnection::push_request_headers() {
|
||||||
|
if (downstream_->get_request_header_sent()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &downstream_hostport = addr_->hostport;
|
const auto &downstream_hostport = addr_->hostport;
|
||||||
const auto &req = downstream_->request();
|
const auto &req = downstream_->request();
|
||||||
|
|
||||||
|
@ -1071,6 +1099,30 @@ http_parser_settings htp_hooks = {
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
int HttpDownstreamConnection::write_reuse_first() {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (conn_.tls.ssl) {
|
||||||
|
rv = write_tls();
|
||||||
|
} else {
|
||||||
|
rv = write_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != 0) {
|
||||||
|
return SHRPX_ERR_RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn_.tls.ssl) {
|
||||||
|
do_write_ = &HttpDownstreamConnection::write_tls;
|
||||||
|
} else {
|
||||||
|
do_write_ = &HttpDownstreamConnection::write_clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
reuse_first_write_done_ = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int HttpDownstreamConnection::read_clear() {
|
int HttpDownstreamConnection::read_clear() {
|
||||||
conn_.last_read = ev_now(conn_.loop);
|
conn_.last_read = ev_now(conn_.loop);
|
||||||
|
|
||||||
|
@ -1116,6 +1168,9 @@ int HttpDownstreamConnection::write_clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nwrite < 0) {
|
if (nwrite < 0) {
|
||||||
|
if (!reuse_first_write_done_) {
|
||||||
|
return nwrite;
|
||||||
|
}
|
||||||
// We may have pending data in receive buffer which may contain
|
// We may have pending data in receive buffer which may contain
|
||||||
// part of response body. So keep reading. Invoke read event
|
// part of response body. So keep reading. Invoke read event
|
||||||
// to get read(2) error just in case.
|
// to get read(2) error just in case.
|
||||||
|
@ -1241,6 +1296,9 @@ int HttpDownstreamConnection::write_tls() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nwrite < 0) {
|
if (nwrite < 0) {
|
||||||
|
if (!reuse_first_write_done_) {
|
||||||
|
return nwrite;
|
||||||
|
}
|
||||||
// We may have pending data in receive buffer which may contain
|
// We may have pending data in receive buffer which may contain
|
||||||
// part of response body. So keep reading. Invoke read event
|
// part of response body. So keep reading. Invoke read event
|
||||||
// to get read(2) error just in case.
|
// to get read(2) error just in case.
|
||||||
|
|
|
@ -71,6 +71,7 @@ public:
|
||||||
|
|
||||||
int initiate_connection();
|
int initiate_connection();
|
||||||
|
|
||||||
|
int write_reuse_first();
|
||||||
int read_clear();
|
int read_clear();
|
||||||
int write_clear();
|
int write_clear();
|
||||||
int read_tls();
|
int read_tls();
|
||||||
|
@ -108,6 +109,9 @@ private:
|
||||||
IOControl ioctrl_;
|
IOControl ioctrl_;
|
||||||
http_parser response_htp_;
|
http_parser response_htp_;
|
||||||
ssize_t initial_addr_idx_;
|
ssize_t initial_addr_idx_;
|
||||||
|
// true if first write of reused connection succeeded. For
|
||||||
|
// convenience, this is initialized as true.
|
||||||
|
bool reuse_first_write_done_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -766,7 +766,7 @@ int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -743,7 +743,7 @@ int SpdyUpstream::downstream_write(DownstreamConnection *dconn) {
|
||||||
return downstream_error(dconn, Downstream::EVENT_ERROR);
|
return downstream_error(dconn, Downstream::EVENT_ERROR);
|
||||||
}
|
}
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return rv;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue