-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathpatrol_services.go
141 lines (139 loc) · 5.21 KB
/
patrol_services.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
package patrol
import (
"log"
"sync"
)
func (self *Patrol) shutdownServices() {
var wg sync.WaitGroup
log.Printf("./patrol.shutdownServices(): signalling to all services that we are shutting down!\n")
for _, service := range self.services {
if service.config.TriggerShutdown != nil {
wg.Add(1)
go func(service *Service) {
defer wg.Done()
// call trigger outside of lock
service.config.TriggerShutdown(service)
}(service)
}
}
wg.Wait()
}
func (self *Patrol) runServices() {
var wg sync.WaitGroup
// we're going to ignore any shutdown checks in this function
// we're only interested in the state of shutdown for Services as we're responsible for running AND managing state
for _, service := range self.services {
wg.Add(1)
go func(service *Service) {
defer wg.Done()
// we're not going to defer unlocking our service mutex, we're going to occasionally unlock and allow our tiggers to run
// for example when we check if our service is running, if we call close() we want to trigger our close right away
// if we do not unlock, we could then call startService() without having ever signalled our close trigger
service.o.Lock()
// we have to check if we're running on every loop, regardless if we're disabled
// there's a chance our service could become enabled should we check and find we're running
// if we aren't running and we call close() and call our close trigger
is_running_err := service.isServiceRunning()
is_running := (is_running_err == nil)
// we need to run our state triggers
if is_running {
// we're running!
//log.Printf("./patrol.runServices(): Service ID: %s is running\n", service.id)
if service.config.TriggerRunning != nil {
service.o.Unlock()
service.config.TriggerRunning(service)
service.o.Lock()
}
// if we're disabled or restarting we're going to signal our services to stop
if service.o.IsRestart() {
// signal our service to restart
log.Printf("./patrol.runServices(): Service ID: %s is running AND we're restarting! - Restarting!\n", service.id)
if err := service.restartService(); err != nil {
log.Printf("./patrol.runServices(): Service ID: %s failed to restart: \"%s\"\n", service.id, err)
} else {
log.Printf("./patrol.runServices(): Service ID: %s restarted\n", service.id)
}
// we will only attempt to restart ONCE, we consume restart even if we fail to restart!
service.o.SetRestart(false)
// it's going to ultimately be up to our Service to exit
// we're not going to immediately attempt to start our app on this tick
// in fact, if our app chooses not to exit we will do nothing!
} else if service.o.IsDisabled() {
// signal our service to stop
log.Printf("./patrol.runServices(): Service ID: %s is running AND is disabled! - Stopping!\n", service.id)
if err := service.stopService(); err != nil {
log.Printf("./patrol.runServices(): Service ID: %s failed to stop: \"%s\"\n", service.id, err)
} else {
log.Printf("./patrol.runServices(): Service ID: %s stopped\n", service.id)
}
}
service.o.Unlock()
// we're done!
return
} else {
// we aren't running
if service.o.IsDisabled() {
// service is disabled
//log.Printf("./patrol.runServices(): Service ID: %s is not running AND is disabled! - Reason: \"%s\"\n", service.id, is_running_err)
if service.config.TriggerDisabled != nil {
service.o.Unlock()
service.config.TriggerDisabled(service)
service.o.Lock()
}
// check if we're still disabled
if service.o.IsDisabled() {
// still disabled!!!
// nothing we can do
service.o.Unlock()
// we're done!
return
}
// we're now enabled!!!
log.Printf("./patrol.runServices(): Service ID: %s was disabled and now enabled!\n", service.id)
} else {
// service is enabled and we aren't running
log.Printf("./patrol.runServices(): Service ID: %s was not running, starting! - Reason: \"%s\"\n", service.id, is_running_err)
}
}
// time to start our service!
log.Printf("./patrol.runServices(): Service ID: %s starting!\n", service.id)
if service.config.TriggerStart != nil {
service.o.Unlock()
service.config.TriggerStart(service)
service.o.Lock()
// this will be our LAST chance to check disabled!!
if service.o.IsDisabled() {
// disabled!!!
service.o.Unlock()
// we're done!
log.Printf("./patrol.runServices(): Service ID: %s can't start, we're disabled!\n", service.id)
return
}
}
// run!
if err := service.startService(); err != nil {
log.Printf("./patrol.runServices(): Service ID: %s failed to start: \"%s\"\n", service.id, err)
// call start failed trigger
if service.config.TriggerStartFailed != nil {
service.o.Unlock()
// we're done!
service.config.TriggerStartFailed(service)
return
}
} else {
log.Printf("./patrol.runServices(): Service ID: %s started\n", service.id)
// call started trigger
if service.config.TriggerStarted != nil {
service.o.Unlock()
// we're done!
service.config.TriggerStarted(service)
return
}
}
service.o.Unlock()
// we're done!
return
}(service)
}
wg.Wait()
}