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.
This commit is contained in:
William Lallemand 2023-09-05 16:42:27 +02:00
parent c52948bd2c
commit 6bc00a97da
2 changed files with 58 additions and 0 deletions

View File

@ -1091,6 +1091,7 @@ The following keywords are supported in the "global" section :
- httpclient.retries - httpclient.retries
- httpclient.ssl.ca-file - httpclient.ssl.ca-file
- httpclient.ssl.verify - httpclient.ssl.verify
- httpclient.timeout.connect
- insecure-fork-wanted - insecure-fork-wanted
- insecure-setuid-wanted - insecure-setuid-wanted
- issuers-chain-path - issuers-chain-path
@ -1759,6 +1760,18 @@ httpclient.ssl.verify [none|required]
However, when this option is explicitly enabled it will trigger a However, when this option is explicitly enabled it will trigger a
configuration error if it fails. configuration error if it fails.
httpclient.timeout.connect <timeout>
Set the maximum time to wait for a connection attempt by default for the
httpclient.
Arguments :
<timeout> 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 insecure-fork-wanted
By default HAProxy tries hard to prevent any thread and process creation 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 after it starts. Doing so is particularly important when using Lua files of

View File

@ -56,6 +56,7 @@ static char *resolvers_prefer = NULL;
static int resolvers_disabled = 0; static int resolvers_disabled = 0;
static int httpclient_retries = CONN_RETRIES; 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 --- /* --- This part of the file implement an HTTP client over the CLI ---
* The functions will be starting by "hc_cli" for "httpclient 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->maxconn = 0;
px->accept = NULL; px->accept = NULL;
px->conn_retries = httpclient_retries; px->conn_retries = httpclient_retries;
px->timeout.connect = httpclient_timeout_connect;
px->timeout.client = TICK_ETERNITY; px->timeout.client = TICK_ETERNITY;
/* The HTTP Client use the "option httplog" with the global log server */ /* The HTTP Client use the "option httplog" with the global log server */
px->conf.logformat_string = httpclient_log_format; 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; 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, { static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "httpclient.resolvers.disabled", httpclient_parse_global_resolvers_disabled }, { CFG_GLOBAL, "httpclient.resolvers.disabled", httpclient_parse_global_resolvers_disabled },
{ CFG_GLOBAL, "httpclient.resolvers.id", httpclient_parse_global_resolvers }, { CFG_GLOBAL, "httpclient.resolvers.id", httpclient_parse_global_resolvers },
{ CFG_GLOBAL, "httpclient.resolvers.prefer", httpclient_parse_global_prefer }, { CFG_GLOBAL, "httpclient.resolvers.prefer", httpclient_parse_global_prefer },
{ CFG_GLOBAL, "httpclient.retries", httpclient_parse_global_retries }, { CFG_GLOBAL, "httpclient.retries", httpclient_parse_global_retries },
{ CFG_GLOBAL, "httpclient.timeout.connect", httpclient_parse_global_timeout_connect },
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
{ CFG_GLOBAL, "httpclient.ssl.verify", httpclient_parse_global_verify }, { CFG_GLOBAL, "httpclient.ssl.verify", httpclient_parse_global_verify },
{ CFG_GLOBAL, "httpclient.ssl.ca-file", httpclient_parse_global_ca_file }, { CFG_GLOBAL, "httpclient.ssl.ca-file", httpclient_parse_global_ca_file },