@marcel91200 / caddy Mirror · read-only / commits / 825fe48e
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 12, 07:00 UTC

reverseproxy: Allow `0` as weights for `weighted_round_robin` (#6681)

* Allow 0 as weights Change positive to non-negative * reverseproxy: allow 0 as weighted round robin value * test: add more wrr select test --------- Co-authored-by: peanutduck <peanutduck@yahoo.com>

Sucipto committed Nov 8, 2024 at 05:58 UTC 825fe48e0654dc6e4e065df364a51ea79488e44b
2 files changed +65 -6
modules/caddyhttp/reverseproxy/selectionpolicies.go
+13 -6
@@ -111,8 +111,8 @@ func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser)
111 if err != nil {
112 return d.Errf("invalid weight value '%s': %v", weight, err)
113 }
114 - if weightInt < 1 {
115 - return d.Errf("invalid weight value '%s': weight should be non-zero and positive", weight)
114 + if weightInt < 0 {
115 + return d.Errf("invalid weight value '%s': weight should be non-negative", weight)
116 }
117 r.Weights = append(r.Weights, weightInt)
118 }
@@ -136,8 +136,15 @@ func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request,
136 return pool[0]
137 }
138 var index, totalWeight int
139 + var weights []int
140 +
141 + for _, w := range r.Weights {
142 + if w > 0 {
143 + weights = append(weights, w)
144 + }
145 + }
146 currentWeight := int(atomic.AddUint32(&r.index, 1)) % r.totalWeight
140 - for i, weight := range r.Weights {
147 + for i, weight := range weights {
148 totalWeight += weight
149 if currentWeight < totalWeight {
150 index = i
@@ -145,9 +152,9 @@ func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request,
152 }
153 }
154
148 - upstreams := make([]*Upstream, 0, len(r.Weights))
149 - for _, upstream := range pool {
150 - if !upstream.Available() {
155 + upstreams := make([]*Upstream, 0, len(weights))
156 + for i, upstream := range pool {
157 + if !upstream.Available() || r.Weights[i] == 0 {
158 continue
159 }
160 upstreams = append(upstreams, upstream)
modules/caddyhttp/reverseproxy/selectionpolicies_test.go
+52
@@ -131,6 +131,58 @@ func TestWeightedRoundRobinPolicy(t *testing.T) {
131 }
132 }
133
134 +func TestWeightedRoundRobinPolicyWithZeroWeight(t *testing.T) {
135 + pool := testPool()
136 + wrrPolicy := WeightedRoundRobinSelection{
137 + Weights: []int{0, 2, 1},
138 + totalWeight: 3,
139 + }
140 + req, _ := http.NewRequest("GET", "/", nil)
141 +
142 + h := wrrPolicy.Select(pool, req, nil)
143 + if h != pool[1] {
144 + t.Error("Expected first weighted round robin host to be second host in the pool.")
145 + }
146 +
147 + h = wrrPolicy.Select(pool, req, nil)
148 + if h != pool[2] {
149 + t.Error("Expected second weighted round robin host to be third host in the pool.")
150 + }
151 +
152 + h = wrrPolicy.Select(pool, req, nil)
153 + if h != pool[1] {
154 + t.Error("Expected third weighted round robin host to be second host in the pool.")
155 + }
156 +
157 + // mark second host as down
158 + pool[1].setHealthy(false)
159 + h = wrrPolicy.Select(pool, req, nil)
160 + if h != pool[2] {
161 + t.Error("Expect select next available host.")
162 + }
163 +
164 + h = wrrPolicy.Select(pool, req, nil)
165 + if h != pool[2] {
166 + t.Error("Expect select only available host.")
167 + }
168 + // mark second host as up
169 + pool[1].setHealthy(true)
170 +
171 + h = wrrPolicy.Select(pool, req, nil)
172 + if h != pool[1] {
173 + t.Error("Expect select first host on availability.")
174 + }
175 +
176 + // test next select in full cycle
177 + expected := []*Upstream{pool[1], pool[2], pool[1], pool[1], pool[2], pool[1]}
178 + for i, want := range expected {
179 + got := wrrPolicy.Select(pool, req, nil)
180 + if want != got {
181 + t.Errorf("Selection %d: got host[%s], want host[%s]", i+1, got, want)
182 + }
183 + }
184 +}
185 +
186 func TestLeastConnPolicy(t *testing.T) {
187 pool := testPool()
188 lcPolicy := LeastConnSelection{}