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