diff --git a/alive_guard.go b/alive_guard.go new file mode 100644 index 0000000..18b1df5 --- /dev/null +++ b/alive_guard.go @@ -0,0 +1,46 @@ +package simple_k8s + +import ( + "sync" + "time" + + "google.golang.org/grpc/health" + healthpb "google.golang.org/grpc/health/grpc_health_v1" +) + +type AliveGuard struct { + mutex sync.Mutex + healthCheckServer *health.Server + timeThreshold time.Duration + serviceName string + failed bool +} + +func NewAliveGuard(healtServer *health.Server, threshold time.Duration, serviceName string) *AliveGuard { + return &AliveGuard{ + healthCheckServer: healtServer, + timeThreshold: threshold, + serviceName: serviceName, + failed: false, + } +} + +func (g *AliveGuard) CheckTimeDuration(startTime time.Time) { + if g.failed { + return + } + + if time.Since(startTime) > g.timeThreshold { + g.mutex.Lock() + defer g.mutex.Unlock() + if !g.failed { + g.failed = true + g.healthCheckServer.SetServingStatus(g.serviceName, healthpb.HealthCheckResponse_NOT_SERVING) + } + } + +} + +func GetAppAliveGuard(threshold time.Duration) *AliveGuard { + return NewAliveGuard(healthCheckServer, threshold, "") +} diff --git a/go.mod b/go.mod index fc34c98..5ab0003 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/geniussportsgroup/Slist v1.1.0-pre github.com/geniussportsgroup/treaps v1.3.0-pre2 github.com/stretchr/testify v1.8.4 + google.golang.org/grpc v1.27.1 k8s.io/apimachinery v0.20.2 k8s.io/client-go v0.20.2 @@ -34,6 +35,7 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 6e0a4f4..e177922 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,7 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -389,6 +390,7 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -396,6 +398,7 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/health_check.go b/health_check.go new file mode 100644 index 0000000..721530d --- /dev/null +++ b/health_check.go @@ -0,0 +1,36 @@ +package simple_k8s + +import ( + "fmt" + "log" + "net" + + "google.golang.org/grpc" + "google.golang.org/grpc/health" + healthgrpc "google.golang.org/grpc/health/grpc_health_v1" + healthpb "google.golang.org/grpc/health/grpc_health_v1" +) + +const HealthPort = 9666 +const CheckName = "alive" + +var healthCheckServer *health.Server = &health.Server{} + +func EnableLivelinessCheck() { + + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", HealthPort)) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + s := grpc.NewServer() + *healthCheckServer = *health.NewServer() + healthCheckServer.SetServingStatus(CheckName, healthpb.HealthCheckResponse_SERVING) + healthgrpc.RegisterHealthServer(s, healthCheckServer) + s.Serve(lis) +} + +func DisableLivelinessCheck() { + + healthCheckServer.SetServingStatus(CheckName, healthpb.HealthCheckResponse_NOT_SERVING) +} diff --git a/simple_k8s.go b/simple_k8s.go index bfe5b11..9c609fc 100644 --- a/simple_k8s.go +++ b/simple_k8s.go @@ -226,3 +226,10 @@ func SetTerminationHandlerWithContinuation(TerminationTimeout time.Duration, continuation func(pars ...interface{}), pars ...interface{}) { go TerminationHandlerCont(TerminationTimeout, continuation, pars...) } + +// TerminationAndLivelinessWithContinuation Wrapper for setting the goroutine prepared for handling the SIGTERM +func TerminationAndLivelinessWithContinuation(TerminationTimeout time.Duration, + continuation func(pars ...interface{}), pars ...interface{}) { + go TerminationHandlerCont(TerminationTimeout, continuation, pars...) + go EnableLivelinessCheck() +}