From: Christopher Faulet Date: Wed, 4 Nov 2026 08:40:29 +0000 (+0100) Subject: BUG/MEDIUM: stream: reset analyse_exp when analysers are stripped on error X-Git-Url: https://git.kaiwu.me/$%7BISSUES%7D/static/gitweb.js?a=commitdiff_plain;h=6c5df88df8dedc46b4958fff8d0c2a24ce8bb8b2;p=haproxy.git BUG/MEDIUM: stream: reset analyse_exp when analysers are stripped on error When the client or the server connector reports an error or a timeout that no analyser handled, process_stream() strips all analysers from the corresponding channel to let the error propagate, except the flt_end one. When this happens while an analyser was yielding with the channel's analyse_exp timer armed (e.g. an SPOE event or a Lua action waiting on an external party), the stripped analysers can no longer manage nor reset this timer. If it already expired, update_exp_and_leave() refuses to clear it as long as the AN_*_FLT_END bit is kept for the two-channel filter synchronisation, so t->expire is set to a past date, the task is requeued in the past and process_stream() spins in a tight loop until the watchdog kills the worker. The request-side retry path (http_ana.c, http_req_retry) already resets res->analyse_exp right after the same strip; do the same on both error propagation paths of process_stream() so that an armed analyse timer can never survive the analysers it was armed for. This is the first commit of the series fixing github issue #3559. It must be backported to all stable versions --- diff --git a/src/stream.c b/src/stream.c index 45b2c0946..efa83e1f1 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2385,7 +2385,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) if ((scf->flags & SC_FL_ERROR) || req->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) { /* Report it if the client got an error or a read timeout expired */ req->analysers &= AN_REQ_FLT_END; - channel_auto_close(req); + req->analyse_exp = TICK_ETERNITY; if (scf->flags & SC_FL_ERROR) { if (s->be_tgcounters) _HA_ATOMIC_INC(&s->be_tgcounters->cli_aborts); @@ -2440,6 +2440,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state) else if ((scb->flags & SC_FL_ERROR) || res->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) { /* Report it if the server got an error or a read timeout expired */ res->analysers &= AN_RES_FLT_END; + res->analyse_exp = TICK_ETERNITY; channel_auto_close(res); if (scb->flags & SC_FL_ERROR) { if (s->be_tgcounters)