-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexec.go
64 lines (55 loc) · 1.87 KB
/
exec.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
package piper
import (
"context"
"sync"
)
// execFnType is a method signature for the start / stop methods of the executable interface
type execFnType func(context.Context)
// executable is an interface which exposes the start and stop methods
type executable interface {
start(context.Context)
stop(context.Context)
}
// exec is a struct which implements the executable interface and is used for managing the startup and shutdown of processes
type exec struct {
execMutex sync.Mutex // mutex used to prevent race conditions between start and stop
startOnce sync.Once // used to ensure that the startup function is called only once
stopOnce sync.Once // used to ensure that the shutdown function is called only once
startFn execFnType // callback function called during startup
stopFn execFnType // callback function called during shutdown
}
// newExec creates a pointer to a exec given a startFn and a stopFn
func newExec(startFn, stopFn execFnType) *exec {
return &exec{
startFn: startFn,
stopFn: stopFn,
}
}
// start triggers the startup sequence by calling startFn
func (e *exec) start(ctx context.Context) {
// Lock the mutex to prevent race conditions with Stop
e.execMutex.Lock()
defer e.execMutex.Unlock()
// Do the startup sequence once until the shutdown sequence resets
e.startOnce.Do(func() {
defer func() {
// reset stopOnce so the shutdown sequence can happen again
e.stopOnce = sync.Once{}
}()
e.startFn(ctx)
})
}
// stop triggers the shutdown sequence by calling stopFn
func (e *exec) stop(ctx context.Context) {
// Lock the mutex to prevent race conditions with Start
e.execMutex.Lock()
defer e.execMutex.Unlock()
// Do the shutdown sequence once until the startup sequence resets
e.stopOnce.Do(func() {
defer func() {
// reset startOnce so the startup sequence can happen again
e.startOnce = sync.Once{}
}()
e.stopFn(ctx)
})
}