@@ -44,9 +44,7 @@ type Watchdog struct {
44
44
provider Provider
45
45
// instanceStateMutex used to avoid a race condition under started and shouldStop fields.
46
46
instanceStateMutex sync.Mutex
47
- // started indicates whether the Watchdog has started an Instance.
48
- started bool
49
- // shouldStop indicates whether the Watchdog should stop the Instance.
47
+ // shouldStop indicates whether the Watchdog should be stopped.
50
48
shouldStop bool
51
49
}
52
50
@@ -57,37 +55,48 @@ func NewWatchdog(restartable bool, restartTimeout time.Duration, logger *ttlog.L
57
55
provider : provider }
58
56
59
57
wd .done = make (chan bool , 1 )
60
- wd .shouldStop = false
61
58
62
59
return & wd
63
60
}
64
61
65
62
// Start starts the Instance and signal handling.
66
- func (wd * Watchdog ) Start () {
63
+ func (wd * Watchdog ) Start (preStartAction func () error ) error {
64
+ var err error
65
+ // Create Instance.
66
+ if wd .Instance , err = wd .provider .CreateInstance (wd .logger ); err != nil {
67
+ wd .logger .Printf (`Watchdog(ERROR): "%v".` , err )
68
+ return err
69
+ }
70
+ wd .logger = wd .Instance .logger
71
+ // The signal handling loop must be started before the instance
72
+ // get started for avoiding a race condition between tt start
73
+ // and tt stop. This way we avoid a situation when we receive
74
+ // a signal before starting a handler for it.
75
+ wd .startSignalHandling ()
76
+
77
+ if err = preStartAction (); err != nil {
78
+ wd .logger .Printf (`Pre-start action error: %v` , err )
79
+ // Finish the signal handling goroutine.
80
+ wd .done <- true
81
+ return err
82
+ }
83
+
67
84
// The Instance must be restarted on completion if the "restartable"
68
85
// parameter is set to "true".
69
86
for {
70
87
var err error
71
- // Create Instance.
72
- if wd .Instance , err = wd .provider .CreateInstance (wd .logger ); err != nil {
73
- wd .logger .Printf (`Watchdog(ERROR): "%v".` , err )
74
- break
75
- }
76
- wd .logger = wd .Instance .logger
77
88
78
89
wd .instanceStateMutex .Lock ()
79
- if ! wd .shouldStop {
80
- // Start the Instance.
81
- if err := wd .Instance .Start (); err != nil {
82
- wd .logger .Printf (`Watchdog(ERROR): "%v".` , err )
83
- wd .instanceStateMutex .Unlock ()
84
- break
85
- }
86
- wd .started = true
87
- } else {
90
+ if wd .shouldStop {
88
91
wd .logger .Printf (`Watchdog(ERROR): terminated before instance start.` )
89
92
wd .instanceStateMutex .Unlock ()
90
- return
93
+ return nil
94
+ }
95
+ // Start the Instance.
96
+ if err := wd .Instance .Start (); err != nil {
97
+ wd .logger .Printf (`Watchdog(ERROR): "%v".` , err )
98
+ wd .instanceStateMutex .Unlock ()
99
+ break
91
100
}
92
101
wd .instanceStateMutex .Unlock ()
93
102
@@ -96,10 +105,6 @@ func (wd *Watchdog) Start() {
96
105
wd .logger .Printf (`Watchdog(WARN): "%v".` , err )
97
106
}
98
107
99
- wd .instanceStateMutex .Lock ()
100
- wd .started = false
101
- wd .instanceStateMutex .Unlock ()
102
-
103
108
// Set Instance process completion indication.
104
109
wd .done <- true
105
110
// Wait for the signal processing goroutine to complete.
@@ -125,13 +130,21 @@ func (wd *Watchdog) Start() {
125
130
time .Sleep (wd .restartTimeout )
126
131
127
132
wd .shouldStop = false
133
+
134
+ // Create Instance.
135
+ if wd .Instance , err = wd .provider .CreateInstance (wd .logger ); err != nil {
136
+ wd .logger .Printf (`Watchdog(ERROR): "%v".` , err )
137
+ return err
138
+ }
139
+ wd .logger = wd .Instance .logger
128
140
// Before the restart of an instance start a new signal handling loop.
129
- wd .StartSignalHandling ()
141
+ wd .startSignalHandling ()
130
142
}
143
+ return nil
131
144
}
132
145
133
- // StartSignalHandling starts signal handling in a separate goroutine.
134
- func (wd * Watchdog ) StartSignalHandling () {
146
+ // startSignalHandling starts signal handling in a separate goroutine.
147
+ func (wd * Watchdog ) startSignalHandling () {
135
148
sigChan := make (chan os.Signal , 1 )
136
149
// Reset the signal mask before starting of the new loop.
137
150
signal .Reset ()
@@ -158,22 +171,20 @@ func (wd *Watchdog) StartSignalHandling() {
158
171
switch sig {
159
172
case syscall .SIGINT , syscall .SIGTERM :
160
173
wd .instanceStateMutex .Lock ()
161
- if wd .started {
162
- wd .Instance .Stop (30 * time .Second )
163
- }
164
174
// If we receive one of the "stop" signals, the
165
175
// program should be terminated.
166
176
wd .shouldStop = true
167
177
wd .instanceStateMutex .Unlock ()
178
+ if wd .Instance .IsAlive () {
179
+ wd .Instance .Stop (30 * time .Second )
180
+ }
168
181
case syscall .SIGHUP :
169
182
// Rotate the log files.
170
183
wd .logger .Rotate ()
171
184
default :
172
- wd .instanceStateMutex .Lock ()
173
- if wd .started {
185
+ if wd .Instance .IsAlive () {
174
186
wd .Instance .SendSignal (sig )
175
187
}
176
- wd .instanceStateMutex .Unlock ()
177
188
}
178
189
case _ = <- wd .done :
179
190
return
0 commit comments