-
Notifications
You must be signed in to change notification settings - Fork 0
/
readiness.go
75 lines (59 loc) · 1.38 KB
/
readiness.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
package state
import (
"sync"
)
type readinessState struct {
*group
ready chan struct{}
readyOut chan struct{}
sync.Mutex
}
// ReadinessTail detaches after readiness state initialization.
// The tail is supposed to stay in a background job associated with
// created State as it carries readiness signal.
type ReadinessTail interface {
// Ok sends a signal that background job is ready.
// Not calling Ok will block all parents readiness and cause
// the channel from State's Ready call to block forever.
// After the first call, subsequent calls do nothing.
Ok()
}
func (r *readinessState) Ok() {
r.Lock()
defer r.Unlock()
select {
case <-r.ready:
// Already ready
default:
close(r.ready)
}
}
func WithReadiness(children ...State) (State, ReadinessTail) {
m := withReadiness(children...)
return m, m
}
func withReadiness(children ...State) *readinessState {
s := &readinessState{
group: merge(children...),
ready: make(chan struct{}),
}
return s
}
func (r *readinessState) Ready() <-chan struct{} {
r.Lock()
defer r.Unlock()
if r.readyOut != nil {
// To avoid memory leaks - readyOut channel is created only once
return r.readyOut
}
r.readyOut = make(chan struct{})
go func() {
<-r.group.Ready()
<-r.ready
close(r.readyOut)
}()
return r.readyOut
}
func (r *readinessState) DependsOn(children ...State) State {
return withDependency(r, children...)
}