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, 22:00 UTC
reverseproxy: Fix retries on "upstreams unavailable" error (#5841)
Francis Lavoie committed
Oct 10, 2023 at 18:07 UTC
2a6859a5e46227473220c653668fa9da9f00b14e
1 file changed
+17
-9
modules/caddyhttp/reverseproxy/reverseproxy.go
+17
-9
@@ -357,7 +357,7 @@ func (h *Handler) Provision(ctx caddy.Context) error {
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 {
360
+ if h.HealthChecks.Passive.MaxFails == 0 {
361
h.HealthChecks.Passive.MaxFails = 1
362
}
363
}
@@ -480,7 +480,7 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
480
upstream := h.LoadBalancing.SelectionPolicy.Select(upstreams, r, w)
481
if upstream == nil {
482
if proxyErr == nil {
483
- proxyErr = caddyhttp.Error(http.StatusServiceUnavailable, fmt.Errorf("no upstreams available"))
483
+ proxyErr = caddyhttp.Error(http.StatusServiceUnavailable, noUpstreamsAvailable)
484
}
485
if !h.LoadBalancing.tryAgain(h.ctx, start, retries, proxyErr, r) {
486
return true, proxyErr
@@ -1010,17 +1010,23 @@ func (lb LoadBalancing) tryAgain(ctx caddy.Context, start time.Time, retries int
1010
// should be safe to retry, since without a connection, no
1011
// HTTP request can be transmitted; but if the error is not
1012
// specifically a dialer error, we need to be careful
1013
- if _, ok := proxyErr.(DialError); proxyErr != nil && !ok {
1013
+ if proxyErr != nil {
1014
+ _, isDialError := proxyErr.(DialError)
1015
+ herr, isHandlerError := proxyErr.(caddyhttp.HandlerError)
1016
+
1017
// if the error occurred after a connection was established,
1018
// we have to assume the upstream received the request, and
1019
// retries need to be carefully decided, because some requests
1020
// are not idempotent
1018
- if lb.RetryMatch == nil && req.Method != "GET" {
1019
- // by default, don't retry requests if they aren't GET
1020
- return false
1021
- }
1022
- if !lb.RetryMatch.AnyMatch(req) {
1023
- return false
1021
+ if !isDialError && !(isHandlerError && errors.Is(herr, noUpstreamsAvailable)) {
1022
+ if lb.RetryMatch == nil && req.Method != "GET" {
1023
+ // by default, don't retry requests if they aren't GET
1024
+ return false
1025
+ }
1026
+
1027
+ if !lb.RetryMatch.AnyMatch(req) {
1028
+ return false
1029
+ }
1030
}
1031
}
1032
@@ -1421,6 +1427,8 @@ func (c ignoreClientGoneContext) Err() error {
1427
// from the proxy handler.
1428
const proxyHandleResponseContextCtxKey caddy.CtxKey = "reverse_proxy_handle_response_context"
1429
1430
+var noUpstreamsAvailable = fmt.Errorf("no upstreams available")
1431
+
1432
// Interface guards
1433
var (
1434
_ caddy.Provisioner = (*Handler)(nil)