-
-
Notifications
You must be signed in to change notification settings - Fork 33
/
health_checks.go
125 lines (114 loc) · 2.58 KB
/
health_checks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package health
import (
"errors"
"fmt"
"time"
"github.com/InVisionApp/go-health/v2"
"github.com/InVisionApp/go-health/v2/checkers"
"github.com/rs/zerolog/log"
)
const (
OK = "ok"
)
type Prober struct {
probe Probe
name string
onCheckEndFunc func(bool, bool, string)
hc *health.Health
stopped bool
}
func New(name string, probe Probe, onCheckEnd func(bool, bool, string)) (*Prober, error) {
probe.validateAndSetDefaults()
p := &Prober{
probe: probe,
name: name,
onCheckEndFunc: onCheckEnd,
hc: health.New(),
stopped: false,
}
p.hc.DisableLogging()
if probe.Exec != nil {
err := p.addProber(p.getExecChecker)
if err != nil {
return nil, err
}
return p, err
}
if probe.HttpGet != nil {
err := p.addProber(p.getHttpChecker)
if err != nil {
return nil, err
}
return p, err
}
return nil, fmt.Errorf("no probes [http_get, exec] configured for %s", name)
}
func (p *Prober) Start() {
go func() {
p.stopped = false
time.Sleep(time.Duration(p.probe.InitialDelay) * time.Second)
if p.stopped {
return
}
err := p.hc.Start()
if err != nil && !errors.Is(err, health.ErrAlreadyRunning) {
log.Error().Err(err).Msgf("%s failed to start monitoring", p.name)
return
}
log.Debug().Msgf("%s started monitoring", p.name)
}()
}
func (p *Prober) Stop() {
if p.hc != nil {
_ = p.hc.Stop()
p.stopped = true
}
}
func (p *Prober) healthCheckCompleted(state *health.State) {
fatal := false
ok := false
if state.ContiguousFailures == int64(p.probe.FailureThreshold) {
fatal = true
}
if state.Status == OK {
ok = true
}
if p.stopped {
return
}
p.onCheckEndFunc(ok, fatal, state.Err)
}
func (p *Prober) addProber(factory func() (health.ICheckable, error)) error {
checker, err := factory()
if err != nil {
return err
}
return p.hc.AddCheck(&health.Config{
Name: p.name,
Checker: checker,
Interval: time.Duration(p.probe.PeriodSeconds) * time.Second,
Fatal: false,
OnComplete: p.healthCheckCompleted,
})
}
func (p *Prober) getHttpChecker() (health.ICheckable, error) {
url, err := p.probe.HttpGet.getUrl()
if err != nil {
return nil, err
}
checker, err := checkers.NewHTTP(&checkers.HTTPConfig{
URL: url,
Timeout: time.Duration(p.probe.TimeoutSeconds) * time.Second,
})
if err != nil {
return nil, err
}
return checker, nil
}
func (p *Prober) getExecChecker() (health.ICheckable, error) {
return &execChecker{
command: p.probe.Exec.Command,
timeout: p.probe.TimeoutSeconds,
workingDir: p.probe.Exec.WorkingDir,
}, nil
}