Selection must only ever consider backends that can take work. Today you build Available - the filtered, order-preserving view of the pool that every selection algorithm will choose from.
Return the backends that are up, in pool order, skipping any that are down.
Every selection algorithm in the next chapter answers the same question - “which
backend gets this request?” - and none of them should ever answer with a backend
that is down. Rather than teach each algorithm to check health itself, build the
filter once: Available returns the subset of the pool that is currently up,
keeping the original order so round-robin and weighted selection stay
deterministic.
This one method is the seam between health and selection. Later, when a backend is
Draining as well as Down, Available is the single place that decides it no
longer takes new work - so a draining backend disappears from selection for free,
without touching any algorithm. Selecting from an empty Available (every backend
down) is the all-down case you will handle explicitly near the end.
func (p *Pool) Available() []*Backend {var out []*Backendfor _, b := range p.backends {if b.IsUp() { out = append(out, b) }}return out}