2024-04-10 00:06:50 +03:00
|
|
|
package health_handler
|
2023-02-26 14:51:34 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
codecpb "go.unistack.org/micro-proto/v3/codec"
|
|
|
|
"go.unistack.org/micro/v3/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ HealthServiceServer = &Handler{}
|
|
|
|
|
|
|
|
type Handler struct {
|
|
|
|
opts Options
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:47:30 +03:00
|
|
|
type (
|
|
|
|
CheckFunc func(context.Context) error
|
|
|
|
Option func(*Options)
|
|
|
|
)
|
2023-02-26 14:51:34 +03:00
|
|
|
|
2024-12-02 15:47:30 +03:00
|
|
|
type Stater interface {
|
|
|
|
Live() bool
|
|
|
|
Ready() bool
|
|
|
|
Health() bool
|
|
|
|
}
|
2023-02-26 14:51:34 +03:00
|
|
|
|
|
|
|
type Options struct {
|
2024-12-02 15:47:30 +03:00
|
|
|
Version string
|
|
|
|
Name string
|
|
|
|
Staters []Stater
|
|
|
|
LiveChecks []CheckFunc
|
|
|
|
ReadyChecks []CheckFunc
|
|
|
|
HealthChecks []CheckFunc
|
|
|
|
}
|
|
|
|
|
|
|
|
func Service(s ...Stater) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.Staters = append(o.Staters, s...)
|
|
|
|
}
|
2023-02-26 14:51:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func LiveChecks(fns ...CheckFunc) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.LiveChecks = append(o.LiveChecks, fns...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ReadyChecks(fns ...CheckFunc) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.ReadyChecks = append(o.ReadyChecks, fns...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:47:30 +03:00
|
|
|
func HealthChecks(fns ...CheckFunc) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.HealthChecks = append(o.HealthChecks, fns...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-26 14:51:34 +03:00
|
|
|
func Name(name string) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.Name = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Version(version string) Option {
|
|
|
|
return func(o *Options) {
|
|
|
|
o.Version = version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewHandler(opts ...Option) *Handler {
|
|
|
|
options := Options{}
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
|
|
|
return &Handler{opts: options}
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:47:30 +03:00
|
|
|
func (h *Handler) Healthy(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
for _, s := range h.opts.Staters {
|
|
|
|
if !s.Health() {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, fn := range h.opts.HealthChecks {
|
|
|
|
if err = fn(ctx); err != nil {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-26 14:51:34 +03:00
|
|
|
func (h *Handler) Live(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
|
|
|
var err error
|
2024-12-02 15:47:30 +03:00
|
|
|
|
|
|
|
for _, s := range h.opts.Staters {
|
|
|
|
if !s.Live() {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-26 14:51:34 +03:00
|
|
|
for _, fn := range h.opts.LiveChecks {
|
|
|
|
if err = fn(ctx); err != nil {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
2024-12-02 15:47:30 +03:00
|
|
|
|
2023-02-26 14:51:34 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Handler) Ready(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
|
|
|
var err error
|
2024-12-02 15:47:30 +03:00
|
|
|
|
|
|
|
for _, s := range h.opts.Staters {
|
|
|
|
if !s.Ready() {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-26 14:51:34 +03:00
|
|
|
for _, fn := range h.opts.ReadyChecks {
|
|
|
|
if err = fn(ctx); err != nil {
|
|
|
|
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Handler) Version(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
|
|
|
rsp.Data = []byte(h.opts.Version)
|
|
|
|
return nil
|
|
|
|
}
|