mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MINOR: stream: Support dynamic changes of the number of connection retries
Thanks to the previous patch, it is now possible to add an action to dynamically change the maxumum number of connection retires for a stream. "set-retries" action may now be used to do so, from a "tcp-request content" or a "http-request" rule. This action accepts an expression or an integer between 0 and 100. The integer value is checked during the configuration parsing and leads to an error if it is not in the expected range. However, for the expression, the value is retrieve at runtime. So, invalid value are just ignored. Too high value is forbidden to avoid any trouble. 100 retries seems already be an amazingly hight value. In addition, the option is only available on backend or listen sections. Because the max retries is limited to 100 at most, it can be stored as a unsigned short. This save some space in the stream structure.
This commit is contained in:
parent
91e785edc9
commit
6a94b7419e
@ -14595,6 +14595,7 @@ set-priority-class - - - X - X -
|
|||||||
set-priority-offset - - - X - X - -
|
set-priority-offset - - - X - X - -
|
||||||
--keyword---------------QUIC--Ini---TCP--RqCon-RqSes-RqCnt-RsCnt---HTTP--Req-Res-Aft-
|
--keyword---------------QUIC--Ini---TCP--RqCon-RqSes-RqCnt-RsCnt---HTTP--Req-Res-Aft-
|
||||||
set-query - - - - - X - -
|
set-query - - - - - X - -
|
||||||
|
set-retries - - - X - X - -
|
||||||
set-src - X X X - X - -
|
set-src - X X X - X - -
|
||||||
set-src-port - X X X - X - -
|
set-src-port - X X X - X - -
|
||||||
set-status - - - - - - X X
|
set-status - - - - - - X X
|
||||||
@ -15772,6 +15773,22 @@ set-query <fmt>
|
|||||||
http-request set-query %[query,regsub(%3D,=,g)]
|
http-request set-query %[query,regsub(%3D,=,g)]
|
||||||
|
|
||||||
|
|
||||||
|
set-retries <int> | <epxr>
|
||||||
|
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
|
- | - | - | X | - | X | - | -
|
||||||
|
|
||||||
|
This action overrides the specified "retries" value for the current stream
|
||||||
|
only. It can be an integer value, in the range [0, 100], or an expression
|
||||||
|
which must return a integer in the range [0, 100].
|
||||||
|
|
||||||
|
Note that this action is only relevant on the backend side and thus this rule
|
||||||
|
is only available for the proxies with backend capability. It is also not
|
||||||
|
allowed in "defaults" sections.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
tcp-request content set-retries 3
|
||||||
|
http-request set-retries var(txn.retries)
|
||||||
|
|
||||||
set-src <expr>
|
set-src <expr>
|
||||||
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
Usable in: QUIC Ini| TCP RqCon| RqSes| RqCnt| RsCnt| HTTP Req| Res| Aft
|
||||||
- | X | X | X | - | X | - | -
|
- | X | X | X | - | X | - | -
|
||||||
|
@ -234,7 +234,6 @@ struct stream {
|
|||||||
* This is a bit field of TASK_WOKEN_* */
|
* This is a bit field of TASK_WOKEN_* */
|
||||||
int conn_retries; /* number of connect retries performed */
|
int conn_retries; /* number of connect retries performed */
|
||||||
unsigned int conn_exp; /* wake up time for connect, queue, turn-around, ... */
|
unsigned int conn_exp; /* wake up time for connect, queue, turn-around, ... */
|
||||||
unsigned int max_retries; /* Maximum number of connection retried (=0 is backend is not set) */
|
|
||||||
unsigned int conn_err_type; /* first error detected, one of STRM_ET_* */
|
unsigned int conn_err_type; /* first error detected, one of STRM_ET_* */
|
||||||
|
|
||||||
struct stream *parent; /* Pointer to the parent stream, if any. NULL most of time */
|
struct stream *parent; /* Pointer to the parent stream, if any. NULL most of time */
|
||||||
@ -248,8 +247,8 @@ struct stream {
|
|||||||
uint64_t cpu_time; /* total CPU time consumed */
|
uint64_t cpu_time; /* total CPU time consumed */
|
||||||
struct freq_ctr call_rate; /* stream task call rate without making progress */
|
struct freq_ctr call_rate; /* stream task call rate without making progress */
|
||||||
|
|
||||||
|
unsigned short max_retries; /* Maximum number of connection retried (=0 is backend is not set) */
|
||||||
short store_count;
|
short store_count;
|
||||||
/* 2 unused bytes here */
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct stksess *ts;
|
struct stksess *ts;
|
||||||
|
88
src/stream.c
88
src/stream.c
@ -430,7 +430,8 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer
|
|||||||
|
|
||||||
s->task = t;
|
s->task = t;
|
||||||
s->pending_events = 0;
|
s->pending_events = 0;
|
||||||
s->conn_retries = s->max_retries = 0;
|
s->conn_retries = 0;
|
||||||
|
s->max_retries = 0;
|
||||||
s->conn_exp = TICK_ETERNITY;
|
s->conn_exp = TICK_ETERNITY;
|
||||||
s->conn_err_type = STRM_ET_NONE;
|
s->conn_err_type = STRM_ET_NONE;
|
||||||
s->prev_conn_state = SC_ST_INI;
|
s->prev_conn_state = SC_ST_INI;
|
||||||
@ -1123,7 +1124,7 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Se the max connection retries for the stream. */
|
/* Se the max connection retries for the stream. may be overwriten later */
|
||||||
s->max_retries = s->be->conn_retries;
|
s->max_retries = s->be->conn_retries;
|
||||||
|
|
||||||
/* we don't want to run the TCP or HTTP filters again if the backend has not changed */
|
/* we don't want to run the TCP or HTTP filters again if the backend has not changed */
|
||||||
@ -2893,6 +2894,87 @@ struct ist stream_generate_unique_id(struct stream *strm, struct lf_expr *format
|
|||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* All supported ACL keywords must be declared here. */
|
/* All supported ACL keywords must be declared here. */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
static enum act_return stream_action_set_retries(struct act_rule *rule, struct proxy *px,
|
||||||
|
struct session *sess, struct stream *s, int flags)
|
||||||
|
{
|
||||||
|
struct sample *smp;
|
||||||
|
|
||||||
|
if (!rule->arg.expr_int.expr)
|
||||||
|
s->max_retries = rule->arg.expr_int.value;
|
||||||
|
else {
|
||||||
|
smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr_int.expr, SMP_T_SINT);
|
||||||
|
if (!smp || smp->data.u.sint < 0 || smp->data.u.sint > 100)
|
||||||
|
goto end;
|
||||||
|
s->max_retries = smp->data.u.sint;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return ACT_RET_CONT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse a "set-retries" action. It takes the level value as argument. It
|
||||||
|
* returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
|
||||||
|
*/
|
||||||
|
static enum act_parse_ret stream_parse_set_retries(const char **args, int *cur_arg, struct proxy *px,
|
||||||
|
struct act_rule *rule, char **err)
|
||||||
|
{
|
||||||
|
struct sample_expr *expr;
|
||||||
|
char *endp;
|
||||||
|
unsigned int where;
|
||||||
|
|
||||||
|
if (!*args[*cur_arg]) {
|
||||||
|
bad_retries:
|
||||||
|
memprintf(err, "expects exactly 1 argument (an expression or an integer between 1 and 100)");
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
if (!(px->cap & PR_CAP_BE)) {
|
||||||
|
memprintf(err, "'%s' only available in backend or listen section", args[0]);
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
if (px->cap & PR_CAP_DEF) {
|
||||||
|
memprintf(err, "'%s' is not allowed in 'defaults' sections", args[0]);
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* value may be either an unsigned integer or an expression */
|
||||||
|
rule->arg.expr_int.expr = NULL;
|
||||||
|
rule->arg.expr_int.value = strtol(args[*cur_arg], &endp, 0);
|
||||||
|
if (*endp == '\0') {
|
||||||
|
if (rule->arg.expr_int.value < 0 || rule->arg.expr_int.value > 100) {
|
||||||
|
memprintf(err, "expects an expression or an integer between 1 and 100");
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
/* valid unsigned integer */
|
||||||
|
(*cur_arg)++;
|
||||||
|
}
|
||||||
|
else { /* invalid unsigned integer, fallback to expr */
|
||||||
|
expr = sample_parse_expr((char **)args, cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
|
||||||
|
if (!expr)
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
where = 0;
|
||||||
|
if (px->cap & PR_CAP_FE)
|
||||||
|
where |= SMP_VAL_FE_HRQ_HDR;
|
||||||
|
if (px->cap & PR_CAP_BE)
|
||||||
|
where |= SMP_VAL_BE_HRQ_HDR;
|
||||||
|
|
||||||
|
if (!(expr->fetch->val & where)) {
|
||||||
|
memprintf(err,
|
||||||
|
"fetch method '%s' extracts information from '%s', none of which is available here",
|
||||||
|
args[*cur_arg-1], sample_src_names(expr->fetch->use));
|
||||||
|
free(expr);
|
||||||
|
return ACT_RET_PRS_ERR;
|
||||||
|
}
|
||||||
|
rule->arg.expr_int.expr = expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register processing function. */
|
||||||
|
rule->action = ACT_CUSTOM;
|
||||||
|
rule->action_ptr = stream_action_set_retries;
|
||||||
|
rule->release_ptr = release_expr_int_action;
|
||||||
|
return ACT_RET_PRS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static enum act_return stream_action_set_log_level(struct act_rule *rule, struct proxy *px,
|
static enum act_return stream_action_set_log_level(struct act_rule *rule, struct proxy *px,
|
||||||
struct session *sess, struct stream *s, int flags)
|
struct session *sess, struct stream *s, int flags)
|
||||||
{
|
{
|
||||||
@ -3907,6 +3989,7 @@ INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
|
|||||||
|
|
||||||
/* main configuration keyword registration. */
|
/* main configuration keyword registration. */
|
||||||
static struct action_kw_list stream_tcp_req_keywords = { ILH, {
|
static struct action_kw_list stream_tcp_req_keywords = { ILH, {
|
||||||
|
{ "set-retries", stream_parse_set_retries },
|
||||||
{ "set-log-level", stream_parse_set_log_level },
|
{ "set-log-level", stream_parse_set_log_level },
|
||||||
{ "set-nice", stream_parse_set_nice },
|
{ "set-nice", stream_parse_set_nice },
|
||||||
{ "switch-mode", stream_parse_switch_mode },
|
{ "switch-mode", stream_parse_switch_mode },
|
||||||
@ -3926,6 +4009,7 @@ static struct action_kw_list stream_tcp_res_keywords = { ILH, {
|
|||||||
INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &stream_tcp_res_keywords);
|
INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &stream_tcp_res_keywords);
|
||||||
|
|
||||||
static struct action_kw_list stream_http_req_keywords = { ILH, {
|
static struct action_kw_list stream_http_req_keywords = { ILH, {
|
||||||
|
{ "set-retries", stream_parse_set_retries },
|
||||||
{ "set-log-level", stream_parse_set_log_level },
|
{ "set-log-level", stream_parse_set_log_level },
|
||||||
{ "set-nice", stream_parse_set_nice },
|
{ "set-nice", stream_parse_set_nice },
|
||||||
{ "use-service", stream_parse_use_service },
|
{ "use-service", stream_parse_use_service },
|
||||||
|
Loading…
Reference in New Issue
Block a user