-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathpatrol.go
170 lines (164 loc) · 3.71 KB
/
patrol.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package patrol
import (
"log"
"os"
"sabey.co/patrol/cas"
"sync"
"time"
)
const (
TICKEVERY_MIN = 5
TICKEVERY_MAX = 120
TICKEVERY_DEFAULT = 15
HISTORY_MIN = 5
HISTORY_MAX = 1000
HISTORY_DEFAULT = 100
)
const (
PATROL_ENV_UNITTEST_KEY = `PATROL_UNITTEST`
PATROL_ENV_UNITTEST_VALUE = `I KNOW WHAT I AM DOING`
)
func CreatePatrol(
config *Config,
) (
*Patrol,
error,
) {
// deference
config = config.Clone()
if !config.IsValid() {
return nil, ERR_CONFIG_NIL
}
if err := config.Validate(); err != nil {
return nil, err
}
p := &Patrol{
instance_id: uuidMust(uuidV4()),
config: config,
apps: make(map[string]*App),
services: make(map[string]*Service),
}
// we're going to check if we're unittesting
// this isn't the ideal way to do this, but it will work
if os.Getenv(PATROL_ENV_UNITTEST_KEY) == PATROL_ENV_UNITTEST_VALUE {
log.Println("./patrol.CreatePatrol(): We are running in unittesting mode!")
// unittesting!!!
p.config.unittesting = true
// we're going to override tickevery so we don't have to wait ages for unittests
p.config.TickEvery = 2
// we won't start HTTP/UDP apps until PingTimeout * 2 on boot
// we're going to override that it's at least something low
p.config.PingTimeout = 3
}
// add apps
for id, app := range config.Apps {
p.apps[id] = &App{
id: id,
patrol: p,
config: app,
o: cas.CreateApp(app.Disabled),
}
// add preexisting keyvalues
p.apps[id].ReplaceKeyValue(app.KeyValue)
}
// add services
for id, service := range config.Services {
p.services[id] = &Service{
id: id,
patrol: p,
config: service,
o: cas.CreateService(service.Disabled),
}
// add preexisting keyvalues
p.services[id].ReplaceKeyValue(service.KeyValue)
}
if config.TriggerStart != nil {
// start patrol
// we do NOT need to use a goroutine
// we'll use this as additional validation
// if this returns an error we WONT return a patrol object
if err := config.TriggerStart(p); err != nil {
// failed to trigger start
return nil, err
}
}
return p, nil
}
type Patrol struct {
// safe
// instance ID never changes once a Patrol object is created!
instance_id string
config *Config
apps map[string]*App
services map[string]*Service
// unsafe
shutdown bool
// ticker
ticker_running time.Time
ticker_stop bool
mu sync.RWMutex
}
func (self *Patrol) IsValid() bool {
if self == nil {
return false
}
return self.config.IsValid()
}
func (self *Patrol) GetInstanceID() string {
return self.instance_id
}
func (self *Patrol) IsRunning() bool {
self.mu.RLock()
defer self.mu.RUnlock()
return !self.ticker_running.IsZero()
}
func (self *Patrol) GetStarted() time.Time {
self.mu.RLock()
defer self.mu.RUnlock()
return self.ticker_running
}
func (self *Patrol) GetConfig() *Config {
return self.config.Clone()
}
func (self *Patrol) GetApps() map[string]*App {
// derefence
apps := make(map[string]*App)
for k, v := range self.apps {
apps[k] = v
}
return apps
}
func (self *Patrol) GetApp(
key string,
) *App {
return self.apps[key]
}
func (self *Patrol) GetServices() map[string]*Service {
// derefence
services := make(map[string]*Service)
for k, v := range self.services {
services[k] = v
}
return services
}
func (self *Patrol) GetService(
key string,
) *Service {
return self.services[key]
}
func (self *Patrol) Shutdown() {
self.mu.Lock()
defer self.mu.Unlock()
if !self.shutdown && self.config.TriggerShutdown != nil {
// never shutdown
// use goroutine to avoid deadlock
go self.config.TriggerShutdown(self)
}
self.shutdown = true
self.stop()
}
func (self *Patrol) IsShutdown() bool {
self.mu.RLock()
defer self.mu.RUnlock()
return self.shutdown
}