From aeea18be86b7a91cbc87be69a817a41ecff951de Mon Sep 17 00:00:00 2001 From: D'Ali Ben Macha Date: Tue, 3 Nov 2026 08:01:28 +0100 Subject: [PATCH] reverseproxy: skip unavailable upstream with a single weighted_round_robin weight (#8320) With fewer than two weights, WeightedRoundRobinSelection returned the first upstream without checking that it is available. --- .../reverseproxy/selectionpolicies.go | 3 +++ .../reverseproxy/selectionpolicies_test.go | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/modules/caddyhttp/reverseproxy/selectionpolicies.go b/modules/caddyhttp/reverseproxy/selectionpolicies.go index ff4c9953f..431a2fde0 100644 --- a/modules/caddyhttp/reverseproxy/selectionpolicies.go +++ b/modules/caddyhttp/reverseproxy/selectionpolicies.go @@ -146,6 +146,9 @@ func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request, return nil } if len(r.Weights) < 2 { + if !pool[0].Available() { + return nil + } return pool[0] } var index, totalWeight int diff --git a/modules/caddyhttp/reverseproxy/selectionpolicies_test.go b/modules/caddyhttp/reverseproxy/selectionpolicies_test.go index b40674ae6..6813ec036 100644 --- a/modules/caddyhttp/reverseproxy/selectionpolicies_test.go +++ b/modules/caddyhttp/reverseproxy/selectionpolicies_test.go @@ -148,6 +148,24 @@ func TestWeightedRoundRobinPolicyFewerWeightsThanUpstreams(t *testing.T) { } } +func TestWeightedRoundRobinPolicySingleWeight(t *testing.T) { + pool := testPool() + wrrPolicy := WeightedRoundRobinSelection{ + Weights: []int{1}, + totalWeight: 1, + } + req, _ := http.NewRequest("GET", "/", nil) + + if h := wrrPolicy.Select(pool, req, nil); h != pool[0] { + t.Errorf("got %v, want the only weighted host %v", h, pool[0]) + } + + pool[0].setHealthy(false) + if h := wrrPolicy.Select(pool, req, nil); h != nil { + t.Errorf("got %v, want nil when the only weighted host is unavailable", h) + } +} + func TestWeightedRoundRobinSelection_Validate(t *testing.T) { tests := []struct { name string