@marcel91200 / caddy Mirror · read-only / commits / 936ee918
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, 23:15 UTC

reverseproxy: Always return new upstreams (fix #5736) (#5752)

* reverseproxy: Always return new upstreams (fix #5736) * Fix healthcheck logger race

Matt Holt committed Aug 17, 2023 at 11:33 UTC 936ee918ee00bcdf05d2f44a7fa292c054d64700
2 files changed +27 -19
modules/caddyhttp/reverseproxy/reverseproxy.go
+6 -6
@@ -356,6 +356,7 @@ func (h *Handler) Provision(ctx caddy.Context) error {
356 if h.HealthChecks != nil {
357 // set defaults on passive health checks, if necessary
358 if h.HealthChecks.Passive != nil {
359 + h.HealthChecks.Passive.logger = h.logger.Named("health_checker.passive")
360 if h.HealthChecks.Passive.FailDuration > 0 && h.HealthChecks.Passive.MaxFails == 0 {
361 h.HealthChecks.Passive.MaxFails = 1
362 }
@@ -1077,12 +1078,11 @@ func (h Handler) provisionUpstream(upstream *Upstream) {
1078 // without MaxRequests), copy the value into this upstream, since the
1079 // value in the upstream (MaxRequests) is what is used during
1080 // availability checks
1080 - if h.HealthChecks != nil && h.HealthChecks.Passive != nil {
1081 - h.HealthChecks.Passive.logger = h.logger.Named("health_checker.passive")
1082 - if h.HealthChecks.Passive.UnhealthyRequestCount > 0 &&
1083 - upstream.MaxRequests == 0 {
1084 - upstream.MaxRequests = h.HealthChecks.Passive.UnhealthyRequestCount
1085 - }
1081 + if h.HealthChecks != nil &&
1082 + h.HealthChecks.Passive != nil &&
1083 + h.HealthChecks.Passive.UnhealthyRequestCount > 0 &&
1084 + upstream.MaxRequests == 0 {
1085 + upstream.MaxRequests = h.HealthChecks.Passive.UnhealthyRequestCount
1086 }
1087
1088 // upstreams need independent access to the passive
modules/caddyhttp/reverseproxy/upstreams.go
+21 -13
@@ -114,7 +114,7 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
114 cached := srvs[suAddr]
115 srvsMu.RUnlock()
116 if cached.isFresh() {
117 - return cached.upstreams, nil
117 + return allNew(cached.upstreams), nil
118 }
119
120 // otherwise, obtain a write-lock to update the cached value
@@ -126,7 +126,7 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
126 // have refreshed it in the meantime before we re-obtained our lock
127 cached = srvs[suAddr]
128 if cached.isFresh() {
129 - return cached.upstreams, nil
129 + return allNew(cached.upstreams), nil
130 }
131
132 su.logger.Debug("refreshing SRV upstreams",
@@ -145,7 +145,7 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
145 su.logger.Warn("SRV records filtered", zap.Error(err))
146 }
147
148 - upstreams := make([]*Upstream, len(records))
148 + upstreams := make([]Upstream, len(records))
149 for i, rec := range records {
150 su.logger.Debug("discovered SRV record",
151 zap.String("target", rec.Target),
@@ -153,7 +153,7 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
153 zap.Uint16("priority", rec.Priority),
154 zap.Uint16("weight", rec.Weight))
155 addr := net.JoinHostPort(rec.Target, strconv.Itoa(int(rec.Port)))
156 - upstreams[i] = &Upstream{Dial: addr}
156 + upstreams[i] = Upstream{Dial: addr}
157 }
158
159 // before adding a new one to the cache (as opposed to replacing stale one), make room if cache is full
@@ -170,7 +170,7 @@ func (su SRVUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
170 upstreams: upstreams,
171 }
172
173 - return upstreams, nil
173 + return allNew(upstreams), nil
174 }
175
176 func (su SRVUpstreams) String() string {
@@ -206,7 +206,7 @@ func (SRVUpstreams) formattedAddr(service, proto, name string) string {
206 type srvLookup struct {
207 srvUpstreams SRVUpstreams
208 freshness time.Time
209 - upstreams []*Upstream
209 + upstreams []Upstream
210 }
211
212 func (sl srvLookup) isFresh() bool {
@@ -325,7 +325,7 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
325 cached := aAaaa[auStr]
326 aAaaaMu.RUnlock()
327 if cached.isFresh() {
328 - return cached.upstreams, nil
328 + return allNew(cached.upstreams), nil
329 }
330
331 // otherwise, obtain a write-lock to update the cached value
@@ -337,7 +337,7 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
337 // have refreshed it in the meantime before we re-obtained our lock
338 cached = aAaaa[auStr]
339 if cached.isFresh() {
340 - return cached.upstreams, nil
340 + return allNew(cached.upstreams), nil
341 }
342
343 name := repl.ReplaceAll(au.Name, "")
@@ -348,15 +348,15 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
348 return nil, err
349 }
350
351 - upstreams := make([]*Upstream, len(ips))
351 + upstreams := make([]Upstream, len(ips))
352 for i, ip := range ips {
353 - upstreams[i] = &Upstream{
353 + upstreams[i] = Upstream{
354 Dial: net.JoinHostPort(ip.String(), port),
355 }
356 }
357
358 // before adding a new one to the cache (as opposed to replacing stale one), make room if cache is full
359 - if cached.freshness.IsZero() && len(srvs) >= 100 {
359 + if cached.freshness.IsZero() && len(aAaaa) >= 100 {
360 for randomKey := range aAaaa {
361 delete(aAaaa, randomKey)
362 break
@@ -369,7 +369,7 @@ func (au AUpstreams) GetUpstreams(r *http.Request) ([]*Upstream, error) {
369 upstreams: upstreams,
370 }
371
372 - return upstreams, nil
372 + return allNew(upstreams), nil
373 }
374
375 func (au AUpstreams) String() string { return net.JoinHostPort(au.Name, au.Port) }
@@ -377,7 +377,7 @@ func (au AUpstreams) String() string { return net.JoinHostPort(au.Name, au.Port)
377 type aLookup struct {
378 aUpstreams AUpstreams
379 freshness time.Time
380 - upstreams []*Upstream
380 + upstreams []Upstream
381 }
382
383 func (al aLookup) isFresh() bool {
@@ -483,6 +483,14 @@ func (u *UpstreamResolver) ParseAddresses() error {
483 return nil
484 }
485
486 +func allNew(upstreams []Upstream) []*Upstream {
487 + results := make([]*Upstream, len(upstreams))
488 + for i := range upstreams {
489 + results[i] = &Upstream{Dial: upstreams[i].Dial}
490 + }
491 + return results
492 +}
493 +
494 var (
495 srvs = make(map[string]srvLookup)
496 srvsMu sync.RWMutex