Skip to content

Commit f8dff95

Browse files
committed
reverseproxy: Fix retries on "upstreams unavailable" error
1 parent 58ab3a0 commit f8dff95

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

modules/caddyhttp/reverseproxy/reverseproxy.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func (h *Handler) Provision(ctx caddy.Context) error {
357357
// set defaults on passive health checks, if necessary
358358
if h.HealthChecks.Passive != nil {
359359
h.HealthChecks.Passive.logger = h.logger.Named("health_checker.passive")
360-
if h.HealthChecks.Passive.FailDuration > 0 && h.HealthChecks.Passive.MaxFails == 0 {
360+
if h.HealthChecks.Passive.MaxFails == 0 {
361361
h.HealthChecks.Passive.MaxFails = 1
362362
}
363363
}
@@ -480,7 +480,7 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
480480
upstream := h.LoadBalancing.SelectionPolicy.Select(upstreams, r, w)
481481
if upstream == nil {
482482
if proxyErr == nil {
483-
proxyErr = caddyhttp.Error(http.StatusServiceUnavailable, fmt.Errorf("no upstreams available"))
483+
proxyErr = caddyhttp.Error(http.StatusServiceUnavailable, noUpstreamsAvailable)
484484
}
485485
if !h.LoadBalancing.tryAgain(h.ctx, start, retries, proxyErr, r) {
486486
return true, proxyErr
@@ -1016,17 +1016,23 @@ func (lb LoadBalancing) tryAgain(ctx caddy.Context, start time.Time, retries int
10161016
// should be safe to retry, since without a connection, no
10171017
// HTTP request can be transmitted; but if the error is not
10181018
// specifically a dialer error, we need to be careful
1019-
if _, ok := proxyErr.(DialError); proxyErr != nil && !ok {
1019+
if proxyErr != nil {
1020+
_, isDialError := proxyErr.(DialError)
1021+
herr, isHandlerError := proxyErr.(caddyhttp.HandlerError)
1022+
10201023
// if the error occurred after a connection was established,
10211024
// we have to assume the upstream received the request, and
10221025
// retries need to be carefully decided, because some requests
10231026
// are not idempotent
1024-
if lb.RetryMatch == nil && req.Method != "GET" {
1025-
// by default, don't retry requests if they aren't GET
1026-
return false
1027-
}
1028-
if !lb.RetryMatch.AnyMatch(req) {
1029-
return false
1027+
if !isDialError && !(isHandlerError && errors.Is(herr, noUpstreamsAvailable)) {
1028+
if lb.RetryMatch == nil && req.Method != "GET" {
1029+
// by default, don't retry requests if they aren't GET
1030+
return false
1031+
}
1032+
1033+
if !lb.RetryMatch.AnyMatch(req) {
1034+
return false
1035+
}
10301036
}
10311037
}
10321038

@@ -1427,6 +1433,8 @@ func (c ignoreClientGoneContext) Err() error {
14271433
// from the proxy handler.
14281434
const proxyHandleResponseContextCtxKey caddy.CtxKey = "reverse_proxy_handle_response_context"
14291435

1436+
var noUpstreamsAvailable = fmt.Errorf("no upstreams available")
1437+
14301438
// Interface guards
14311439
var (
14321440
_ caddy.Provisioner = (*Handler)(nil)

0 commit comments

Comments
 (0)