Since commit
9fe72bba3 ("MAJOR: leastconn; Revamp the way servers are
ordered."), the lookup starts at the smallest key recorded in
lbprm.lb_seq, and this key is shared by the active and the backup
trees. Under load it follows the keys of the active servers.
When the last active server goes down or into maintenance, the key is
only reset if it equals the key of that server, which is often not the
case under load. With "option allbackups" the backup tree is then
looked up from that key, and the idle backup servers, whose key is 0,
are not found. fwlc_get_next_server() returns NULL, the streams are
queued in the backend, and without maxconn nothing dequeues them: every
request ends with a 503 after "timeout queue", although a backup server
is up. It only recovers when a server is queued at a lower key again.
Without "option allbackups" the first backup server is used directly
and the problem does not happen.
Fix it by resetting the smallest key when the last active server leaves
the tree.
This fixes GitHub issue #3555. It can be reproduced with an active and
a backup server, "balance leastconn" and "option allbackups", by
setting the active server to maintenance under load.
This should be backported as far as 3.2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Aleksandar Lazic <al-haproxy@none.at>
fwlc_dequeue_srv(srv);
fwlc_remove_from_tree(srv);
+ /*
+ * No more active server, we're switching to backups, let's reset
+ * the smallest key.
+ */
+ if (!(srv->flags & SRV_F_BACKUP) && !p->srv_act)
+ fwlc_set_seq_and_smallest(&p->lbprm, p->lbprm.lb_seq, FWLC_LBPRM_SEQ(p->lbprm.lb_seq) + 1, 0);
+
out_update_backend:
/* check/update tot_used, tot_weight */
update_backend_weight(p);