func (uh *upstreamHost) Fails() int {
	return int(atomic.LoadInt64(&uh.fails))
}
Fails returns the number of recent failures with the upstream.
package reverseproxy
import (
	"context"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"sync/atomic"
	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
type Host interface {
	NumRequests() int
	Fails() int
	Unhealthy() bool
	CountRequest(int) error
	CountFail(int) error
	SetHealthy(bool) (bool, error)
}
type UpstreamPool []*Upstream
type Upstream struct {
	Host `json:"-"`
	Dial string `json:"dial,omitempty"`
	LookupSRV string `json:"lookup_srv,omitempty"`
	MaxRequests int `json:"max_requests,omitempty"`
	activeHealthCheckPort int
	healthCheckPolicy     *PassiveHealthChecks
	cb                    CircuitBreaker
}
func (u Upstream) String() string {
	if u.LookupSRV != "" {
		return u.LookupSRV
	}
	return u.Dial
}
func (u *Upstream) Available() bool {
	return u.Healthy() && !u.Full()
}
func (u *Upstream) Healthy() bool {
	healthy := !u.Host.Unhealthy()
	if healthy && u.healthCheckPolicy != nil {
		healthy = u.Host.Fails() < u.healthCheckPolicy.MaxFails
	}
	if healthy && u.cb != nil {
		healthy = u.cb.OK()
	}
	return healthy
}
func (u *Upstream) Full() bool {
	return u.MaxRequests > 0 && u.Host.NumRequests() >= u.MaxRequests
}
func (u *Upstream) fillDialInfo(r *http.Request) (DialInfo, error) {
	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
	var addr caddy.NetworkAddress
	if u.LookupSRV != "" {
		srvName := repl.ReplaceAll(u.LookupSRV, "")
		_, records, err := net.DefaultResolver.LookupSRV(r.Context(), "", "", srvName)
		if err != nil {
			return DialInfo{}, err
		}
		addr.Network = "tcp"
		addr.Host = records[0].Target
		addr.StartPort, addr.EndPort = uint(records[0].Port), uint(records[0].Port)
	} else {
		var err error
		dial := repl.ReplaceAll(u.Dial, "")
		addr, err = caddy.ParseNetworkAddress(dial)
		if err != nil {
			return DialInfo{}, fmt.Errorf("upstream %s: invalid dial address %s: %v", u.Dial, dial, err)
		}
		if numPorts := addr.PortRangeSize(); numPorts != 1 {
			return DialInfo{}, fmt.Errorf("upstream %s: dial address must represent precisely one socket: %s represents %d",
				u.Dial, dial, numPorts)
		}
	}
	return DialInfo{
		Upstream: u,
		Network:  addr.Network,
		Address:  addr.JoinHostPort(0),
		Host:     addr.Host,
		Port:     strconv.Itoa(int(addr.StartPort)),
	}, nil
}
type upstreamHost struct {
	numRequests int64  
	fails       int64
	unhealthy   int32
}
func (uh *upstreamHost) NumRequests() int {
	return int(atomic.LoadInt64(&uh.numRequests))
}