diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 467a6853..ec1c015a 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -148,6 +148,7 @@ OPTIONS = [ "backend-http2-decoder-dynamic-table-size", "ecdh-curves", "tls-sct-dir", + "backend-connect-timeout", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index a6a1aa6f..7d24dc8e 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1442,6 +1442,7 @@ void fill_default_config(Config *config) { timeoutconf.write = 30_s; // Timeout for pooled (idle) connections timeoutconf.idle_read = 2_s; + timeoutconf.connect = 30_s; timeoutconf.max_backoff = 120_s; } @@ -1787,6 +1788,11 @@ Timeout: Specify write timeout for backend connection. Default: )" << util::duration_str(config->conn.downstream->timeout.write) << R"( + --backend-connect-timeout= + Specify timeout before establishing TCP connection to + backend. + Default: )" + << util::duration_str(config->conn.downstream->timeout.connect) << R"( --backend-keep-alive-timeout= Specify keep-alive timeout for backend connection. Default: )" @@ -2956,6 +2962,8 @@ int main(int argc, char **argv) { required_argument, &flag, 139}, {SHRPX_OPT_ECDH_CURVES.c_str(), required_argument, &flag, 140}, {SHRPX_OPT_TLS_SCT_DIR.c_str(), required_argument, &flag, 141}, + {SHRPX_OPT_BACKEND_CONNECT_TIMEOUT.c_str(), required_argument, &flag, + 142}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3624,6 +3632,11 @@ int main(int argc, char **argv) { // --tls-sct-dir cmdcfgs.emplace_back(SHRPX_OPT_TLS_SCT_DIR, StringRef{optarg}); break; + case 142: + // --backend-connect-timeout + cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_CONNECT_TIMEOUT, + StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index b43db96f..de1525bd 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -1657,6 +1657,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_BACKEND_RESPONSE_BUFFER; } break; + case 't': + if (util::strieq_l("backend-connect-timeou", name, 22)) { + return SHRPX_OPTID_BACKEND_CONNECT_TIMEOUT; + } + break; } break; case 24: @@ -2162,6 +2167,9 @@ int parse_config(Config *config, int optid, const StringRef &opt, return parse_duration(&config->conn.downstream->timeout.read, opt, optarg); case SHRPX_OPTID_BACKEND_WRITE_TIMEOUT: return parse_duration(&config->conn.downstream->timeout.write, opt, optarg); + case SHRPX_OPTID_BACKEND_CONNECT_TIMEOUT: + return parse_duration(&config->conn.downstream->timeout.connect, opt, + optarg); case SHRPX_OPTID_STREAM_READ_TIMEOUT: return parse_duration(&config->http2.timeout.stream_read, opt, optarg); case SHRPX_OPTID_STREAM_WRITE_TIMEOUT: diff --git a/src/shrpx_config.h b/src/shrpx_config.h index cf2e6705..9020ef83 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -310,6 +310,8 @@ constexpr auto SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE = StringRef::from_lit("backend-http2-decoder-dynamic-table-size"); constexpr auto SHRPX_OPT_ECDH_CURVES = StringRef::from_lit("ecdh-curves"); constexpr auto SHRPX_OPT_TLS_SCT_DIR = StringRef::from_lit("tls-sct-dir"); +constexpr auto SHRPX_OPT_BACKEND_CONNECT_TIMEOUT = + StringRef::from_lit("backend-connect-timeout"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -718,6 +720,7 @@ struct DownstreamConfig { ev_tstamp read; ev_tstamp write; ev_tstamp idle_read; + ev_tstamp connect; // The maximum backoff while checking health check for offline // backend or while detaching failed backend from load balancing // group temporarily. @@ -850,6 +853,7 @@ enum { SHRPX_OPTID_API_MAX_REQUEST_BODY, SHRPX_OPTID_BACKEND, SHRPX_OPTID_BACKEND_ADDRESS_FAMILY, + SHRPX_OPTID_BACKEND_CONNECT_TIMEOUT, SHRPX_OPTID_BACKEND_CONNECTIONS_PER_FRONTEND, SHRPX_OPTID_BACKEND_CONNECTIONS_PER_HOST, SHRPX_OPTID_BACKEND_HTTP_PROXY_URI, diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 59fcdbfe..3bdb14c9 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -313,6 +313,8 @@ int Http2Session::initiate_connection() { } } + auto &downstreamconf = *get_config()->conn.downstream; + const auto &proxy = get_config()->downstream_http_proxy; if (!proxy.host.empty() && state_ == DISCONNECTED) { if (LOG_ENABLED(INFO)) { @@ -351,7 +353,7 @@ int Http2Session::initiate_connection() { conn_.wlimit.startw(); - // TODO we should have timeout for connection establishment + conn_.wt.repeat = downstreamconf.timeout.connect; ev_timer_again(conn_.loop, &conn_.wt); write_ = &Http2Session::connected; @@ -484,7 +486,8 @@ int Http2Session::initiate_connection() { if (state_ != CONNECTED) { state_ = CONNECTING; conn_.wlimit.startw(); - // TODO we should have timeout for connection establishment + + conn_.wt.repeat = downstreamconf.timeout.connect; ev_timer_again(conn_.loop, &conn_.wt); } else { conn_.rlimit.startw(); @@ -1857,6 +1860,12 @@ int Http2Session::connected() { SSLOG(INFO, this) << "Connection established"; } + auto &downstreamconf = *get_config()->conn.downstream; + + // Reset timeout for write. Previously, we set timeout for connect. + conn_.wt.repeat = downstreamconf.timeout.write; + ev_timer_again(conn_.loop, &conn_.wt); + conn_.rlimit.startw(); read_ = &Http2Session::read_clear; diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 85bf774e..d548ed90 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -315,7 +315,7 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) { break; } - // TODO we should have timeout for connection establishment + conn_.wt.repeat = downstreamconf.timeout.connect; ev_timer_again(conn_.loop, &conn_.wt); } else { // we may set read timer cb to idle_timeoutcb. Reset again. @@ -1178,6 +1178,12 @@ int HttpDownstreamConnection::connected() { DCLOG(INFO, this) << "Connected to downstream host"; } + auto &downstreamconf = *get_config()->conn.downstream; + + // Reset timeout for write. Previously, we set timeout for connect. + conn_.wt.repeat = downstreamconf.timeout.write; + ev_timer_again(conn_.loop, &conn_.wt); + conn_.rlimit.startw(); ev_set_cb(&conn_.wev, writecb); diff --git a/src/shrpx_live_check.cc b/src/shrpx_live_check.cc index 05f48447..618674b3 100644 --- a/src/shrpx_live_check.cc +++ b/src/shrpx_live_check.cc @@ -252,7 +252,9 @@ int LiveCheck::initiate_connection() { conn_.wlimit.startw(); - // TODO we should have timeout for connection establishment + auto &downstreamconf = *get_config()->conn.downstream; + + conn_.wt.repeat = downstreamconf.timeout.connect; ev_timer_again(conn_.loop, &conn_.wt); return 0; @@ -274,6 +276,12 @@ int LiveCheck::connected() { LOG(INFO) << "Connection established"; } + auto &downstreamconf = *get_config()->conn.downstream; + + // Reset timeout for write. Previously, we set timeout for connect. + conn_.wt.repeat = downstreamconf.timeout.write; + ev_timer_again(conn_.loop, &conn_.wt); + conn_.rlimit.startw(); if (conn_.tls.ssl) {