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
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);
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)