package health
import (
healthpb
)
var (
backoffStrategy = backoff.DefaultExponential
backoffFunc = func( context.Context, int) bool {
:= backoffStrategy.Backoff()
:= time.NewTimer()
select {
case <-.C:
return true
case <-.Done():
.Stop()
return false
}
}
)
func () {
internal.HealthCheckFunc = clientHealthCheck
}
const healthCheckMethod = "/grpc.health.v1.Health/Watch"
func ( context.Context, func(string) (any, error), func(connectivity.State, error), string) error {
:= 0
:
for {
if > 0 && !backoffFunc(, -1) {
return nil
}
++
if .Err() != nil {
return nil
}
(connectivity.Connecting, nil)
, := (healthCheckMethod)
if != nil {
continue
}
, := .(grpc.ClientStream)
if ! {
(connectivity.Ready, nil)
return fmt.Errorf("newStream returned %v (type %T); want grpc.ClientStream", , )
}
if = .SendMsg(&healthpb.HealthCheckRequest{Service: }); != nil && != io.EOF {
continue
}
.CloseSend()
:= new(healthpb.HealthCheckResponse)
for {
= .RecvMsg()
if status.Code() == codes.Unimplemented {
(connectivity.Ready, nil)
return
}
if != nil {
(connectivity.TransientFailure, fmt.Errorf("connection active but received health check RPC error: %v", ))
continue
}
= 0
if .Status == healthpb.HealthCheckResponse_SERVING {
(connectivity.Ready, nil)
} else {
(connectivity.TransientFailure, fmt.Errorf("connection active but health check failed. status=%s", .Status))
}
}
}
}