A recovered backend should rejoin the pool - but cautiously. Recovery marks a down backend up again only after a rise threshold of consecutive successful probes, so one lucky probe does not put a flapping backend back into rotation.
Bring a down backend back up once its consecutive-success streak reaches the rise threshold of 2.
Recovery is the mirror image of ejection, and it completes the health state
machine: Down returns to Up when the consecutive-success streak reaches the
rise threshold. Requiring a run of successes rather than a single one is what
tames flapping - a backend that recovers for one probe and fails the next should
not bounce in and out of rotation, dragging requests toward a server that is not
really well. A modest rise threshold makes the balancer patient about readmission.
The two thresholds together give the classic hysteresis of a health checker: it
takes fall failures to eject and rise successes to readmit, and because failure
and success streaks reset each other, only an unbroken run in one direction moves the
state. Pin the same two edges as ejection - the transition happens at exactly the
threshold, and an interrupting failure resets the streak so recovery has to start
over. With this, a down backend that the active prober finds healthy will climb back
into Available() on its own.
const riseThreshold = 2// extend RecordSuccess to recover a down backend at the threshold:func (b *Backend) RecordSuccess() {b.successStreak++b.failStreak = 0if !b.IsUp() && b.successStreak >= riseThreshold { b.MarkUp() }}