From 6bc00a97da93ff41ae47289b2d6c41f849cb2a20 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Tue, 5 Sep 2023 16:42:27 +0200 Subject: [PATCH] MINOR: httpclient: allow to configure the timeout.connect When using the httpclient, one could be bothered with it returning after a very long time when failing. By default the httpclient has a retries of 3 and a timeout connect of 5s, which can results in pause of 20s upon failure. This patch allows the user to configure the "timeout connect" of the httpclient so it could reduce the time to return an error. This patch helps fixing part of the issue #2269. Could be backported in 2.7 if needed. --- doc/configuration.txt | 13 +++++++++++++ src/http_client.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 982bc6ae5..bbec0aa89 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1091,6 +1091,7 @@ The following keywords are supported in the "global" section : - httpclient.retries - httpclient.ssl.ca-file - httpclient.ssl.verify + - httpclient.timeout.connect - insecure-fork-wanted - insecure-setuid-wanted - issuers-chain-path @@ -1759,6 +1760,18 @@ httpclient.ssl.verify [none|required] However, when this option is explicitly enabled it will trigger a configuration error if it fails. +httpclient.timeout.connect + Set the maximum time to wait for a connection attempt by default for the + httpclient. + + Arguments : + is the timeout value specified in milliseconds by default, but + can be in any other unit if the number is suffixed by the unit, + as explained at the top of this document. + + The default value is 5000ms. + + insecure-fork-wanted By default HAProxy tries hard to prevent any thread and process creation after it starts. Doing so is particularly important when using Lua files of diff --git a/src/http_client.c b/src/http_client.c index cc9a1b012..21fdb80b2 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -56,6 +56,7 @@ static char *resolvers_prefer = NULL; static int resolvers_disabled = 0; static int httpclient_retries = CONN_RETRIES; +static int httpclient_timeout_connect = MS_TO_TICKS(5000); /* --- This part of the file implement an HTTP client over the CLI --- * The functions will be starting by "hc_cli" for "httpclient cli" @@ -1221,6 +1222,7 @@ struct proxy *httpclient_create_proxy(const char *id) px->maxconn = 0; px->accept = NULL; px->conn_retries = httpclient_retries; + px->timeout.connect = httpclient_timeout_connect; px->timeout.client = TICK_ETERNITY; /* The HTTP Client use the "option httplog" with the global log server */ px->conf.logformat_string = httpclient_log_format; @@ -1548,12 +1550,55 @@ static int httpclient_parse_global_retries(char **args, int section_type, struct return 0; } +static int httpclient_parse_global_timeout_connect(char **args, int section_type, struct proxy *curpx, + const struct proxy *defpx, const char *file, int line, + char **err) +{ + const char *res; + unsigned timeout; + + if (too_many_args(1, args, err, NULL)) + return -1; + + if (*(args[1]) == 0) { + ha_alert("parsing [%s:%d] : '%s' expects an integer argument.\n", + file, line, args[0]); + return -1; + } + + res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); + if (res == PARSE_TIME_OVER) { + memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)", + args[1], args[0]); + return -1; + } + else if (res == PARSE_TIME_UNDER) { + memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)", + args[1], args[0]); + return -1; + } + else if (res) { + memprintf(err, "unexpected character '%c' in '%s'", *res, args[0]); + return -1; + } + + if (*args[2] != 0) { + memprintf(err, "'%s' : unexpected extra argument '%s' after value '%s'.", args[0], args[2], args[1]); + return -1; + } + + httpclient_timeout_connect = MS_TO_TICKS(timeout); + + return 0; +} + static struct cfg_kw_list cfg_kws = {ILH, { { CFG_GLOBAL, "httpclient.resolvers.disabled", httpclient_parse_global_resolvers_disabled }, { CFG_GLOBAL, "httpclient.resolvers.id", httpclient_parse_global_resolvers }, { CFG_GLOBAL, "httpclient.resolvers.prefer", httpclient_parse_global_prefer }, { CFG_GLOBAL, "httpclient.retries", httpclient_parse_global_retries }, + { CFG_GLOBAL, "httpclient.timeout.connect", httpclient_parse_global_timeout_connect }, #ifdef USE_OPENSSL { CFG_GLOBAL, "httpclient.ssl.verify", httpclient_parse_global_verify }, { CFG_GLOBAL, "httpclient.ssl.ca-file", httpclient_parse_global_ca_file },