Skip to content

Commit 7c6e8fa

Browse files
committed
TO SQUASH OR REMOVE
1 parent 36e8a3f commit 7c6e8fa

File tree

4 files changed

+69
-49
lines changed

4 files changed

+69
-49
lines changed

cli/running/instance.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ type Instance struct {
5050
waitMutex sync.Mutex
5151
// done represent whether the instance was stopped.
5252
done bool
53+
// stateMutex used to avoid a race condition under started and shouldStop fields.
54+
stateMutex sync.Mutex
55+
// started indicates whether the Watchdog has started an Instance.
56+
started bool
57+
// shouldStop indicates whether the Watchdog should stop the Instance.
58+
shouldStop bool
5359
}
5460

5561
//go:embed lua/launcher.lua

cli/running/running.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -518,21 +518,17 @@ func Start(cmdCtx *cmdcontext.CmdCtx, run *InstanceCtx) error {
518518
provider := providerImpl{cmdCtx: cmdCtx, instanceCtx: run}
519519
wd := NewWatchdog(run.Restartable, 5*time.Second, logger, &provider)
520520

521-
// The signal handling loop must be started before the instance
522-
// get started for avoiding a race condition between tt start
523-
// and tt stop. This way we avoid a situation when we receive
524-
// a signal before starting a handler for it.
525-
wd.StartSignalHandling()
526-
527-
if err := process_utils.CreatePIDFile(run.PIDFile); err != nil {
528-
return err
529-
}
530-
531521
defer func() {
532522
cleanup(run)
533523
}()
534524

535-
wd.Start()
525+
preStartAction := func() error {
526+
if err := process_utils.CreatePIDFile(run.PIDFile); err != nil {
527+
return err
528+
}
529+
return nil
530+
}
531+
wd.Start(preStartAction)
536532
return nil
537533
}
538534

cli/running/watchdog.go

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,6 @@ type Watchdog struct {
4242
// and updating may depend on changing external parameters
4343
// (such as configuration file).
4444
provider Provider
45-
// instanceStateMutex used to avoid a race condition under started and shouldStop fields.
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.
50-
shouldStop bool
5145
}
5246

5347
// NewWatchdog creates a new instance of Watchdog.
@@ -57,48 +51,62 @@ func NewWatchdog(restartable bool, restartTimeout time.Duration, logger *ttlog.L
5751
provider: provider}
5852

5953
wd.done = make(chan bool, 1)
60-
wd.shouldStop = false
54+
wd.Instance.shouldStop = false
6155

6256
return &wd
6357
}
6458

6559
// Start starts the Instance and signal handling.
66-
func (wd *Watchdog) Start() {
60+
func (wd *Watchdog) Start(preStartAction func() error) error {
61+
var err error
62+
// Create Instance.
63+
if wd.Instance, err = wd.provider.CreateInstance(wd.logger); err != nil {
64+
wd.logger.Printf(`Watchdog(ERROR): "%v".`, err)
65+
return err
66+
}
67+
wd.logger = wd.Instance.logger
68+
// The signal handling loop must be started before the instance
69+
// get started for avoiding a race condition between tt start
70+
// and tt stop. This way we avoid a situation when we receive
71+
// a signal before starting a handler for it.
72+
wd.startSignalHandling()
73+
74+
if err = preStartAction(); err != nil {
75+
wd.logger.Printf(`Pre-start action error: %v`, err)
76+
// Finish the signal handling goroutine.
77+
wd.done <- true
78+
return err
79+
}
80+
6781
// The Instance must be restarted on completion if the "restartable"
6882
// parameter is set to "true".
6983
for {
7084
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
7785

78-
wd.stateMutex.Lock()
79-
if !wd.shouldStop {
86+
wd.Instance.stateMutex.Lock()
87+
if !wd.Instance.shouldStop {
8088
// Start the Instance.
8189
if err := wd.Instance.Start(); err != nil {
8290
wd.logger.Printf(`Watchdog(ERROR): "%v".`, err)
83-
wd.stateMutex.Unlock()
91+
wd.Instance.stateMutex.Unlock()
8492
break
8593
}
86-
wd.started = true
94+
wd.Instance.started = true
8795
} else {
8896
wd.logger.Printf(`Watchdog(ERROR): terminated before instance start.`)
89-
wd.stateMutex.Unlock()
90-
return
97+
wd.Instance.stateMutex.Unlock()
98+
return nil
9199
}
92-
wd.stateMutex.Unlock()
100+
wd.Instance.stateMutex.Unlock()
93101

94102
// Wait while the Instance will be terminated.
95103
if err := wd.Instance.Wait(); err != nil {
96104
wd.logger.Printf(`Watchdog(WARN): "%v".`, err)
97105
}
98106

99-
wd.stateMutex.Lock()
100-
wd.started = false
101-
wd.stateMutex.Unlock()
107+
wd.Instance.stateMutex.Lock()
108+
wd.Instance.started = false
109+
wd.Instance.stateMutex.Unlock()
102110

103111
// Set Instance process completion indication.
104112
wd.done <- true
@@ -111,7 +119,7 @@ func (wd *Watchdog) Start() {
111119
wd.logger.Println("Watchdog(ERROR): can't check if the instance is restartable.")
112120
break
113121
}
114-
if wd.shouldStop || !restartable {
122+
if wd.Instance.shouldStop || !restartable {
115123
wd.logger.Println("Watchdog(INFO): the Instance has shutdown.")
116124
break
117125
}
@@ -124,14 +132,22 @@ func (wd *Watchdog) Start() {
124132
}
125133
time.Sleep(wd.restartTimeout)
126134

127-
wd.shouldStop = false
135+
wd.Instance.shouldStop = false
136+
137+
// Create Instance.
138+
if wd.Instance, err = wd.provider.CreateInstance(wd.logger); err != nil {
139+
wd.logger.Printf(`Watchdog(ERROR): "%v".`, err)
140+
return err
141+
}
142+
wd.logger = wd.Instance.logger
128143
// Before the restart of an instance start a new signal handling loop.
129-
wd.StartSignalHandling()
144+
wd.startSignalHandling()
130145
}
146+
return nil
131147
}
132148

133-
// StartSignalHandling starts signal handling in a separate goroutine.
134-
func (wd *Watchdog) StartSignalHandling() {
149+
// startSignalHandling starts signal handling in a separate goroutine.
150+
func (wd *Watchdog) startSignalHandling() {
135151
sigChan := make(chan os.Signal, 1)
136152
// Reset the signal mask before starting of the new loop.
137153
signal.Reset()
@@ -157,23 +173,23 @@ func (wd *Watchdog) StartSignalHandling() {
157173
case sig := <-sigChan:
158174
switch sig {
159175
case syscall.SIGINT, syscall.SIGTERM:
160-
wd.stateMutex.Lock()
161-
if wd.started {
176+
wd.Instance.stateMutex.Lock()
177+
if wd.Instance.started {
162178
wd.Instance.Stop(30 * time.Second)
163179
}
164180
// If we receive one of the "stop" signals, the
165181
// program should be terminated.
166-
wd.shouldStop = true
167-
wd.stateMutex.Unlock()
182+
wd.Instance.shouldStop = true
183+
wd.Instance.stateMutex.Unlock()
168184
case syscall.SIGHUP:
169185
// Rotate the log files.
170186
wd.logger.Rotate()
171187
default:
172-
wd.stateMutex.Lock()
173-
if wd.started {
188+
wd.Instance.stateMutex.Lock()
189+
if wd.Instance.started {
174190
wd.Instance.SendSignal(sig)
175191
}
176-
wd.stateMutex.Unlock()
192+
wd.Instance.stateMutex.Unlock()
177193
}
178194
case _ = <-wd.done:
179195
return

cli/running/watchdog_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ func TestWatchdogBase(t *testing.T) {
112112
t.Cleanup(func() { cleanupWatchdog(wd) })
113113

114114
wdDoneChan := make(chan bool, 1)
115+
testPreAction := func() error { return nil }
115116
go func() {
116-
wd.Start()
117+
wd.Start(testPreAction)
117118
wdDoneChan <- true
118119
}()
119120
waitProcessStart()
@@ -140,8 +141,9 @@ func TestWatchdogNotRestartable(t *testing.T) {
140141
t.Cleanup(func() { cleanupWatchdog(wd) })
141142

142143
wdDoneChan := make(chan bool, 1)
144+
testPreAction := func() error { return nil }
143145
go func() {
144-
wd.Start()
146+
wd.Start(testPreAction)
145147
wdDoneChan <- true
146148
}()
147149
waitProcessStart()

0 commit comments

Comments
 (0)