...
1 package rollouts
2
3 import (
4 "context"
5 "errors"
6 "time"
7 )
8
9 var (
10 ErrInvalidGateState = errors.New("invalid gate state")
11 )
12
13 type GateState bool
14
15 const (
16 Open GateState = true
17 Closed GateState = false
18 )
19
20 type GateApproval string
21
22 const (
23 GateApproved GateApproval = "approved"
24 GatePending GateApproval = "pending"
25 GateDenied GateApproval = "denied"
26 )
27
28
29 type RolloutGate interface {
30 IsOpen() bool
31 }
32
33 var _ RolloutGate = &TimerGate{}
34 var _ RolloutGate = &ApprovalGate{}
35 var _ RolloutGate = &ScheduleGate{}
36
37
38 type TimerGate struct {
39 BaseNode `json:",inline"`
40
41
42
43 StartTime time.Time `json:"startTime"`
44
45
46
47 Delay time.Duration `json:"delayMinutes"`
48
49
50
51 time TimeSource
52 }
53
54 func NewTimerGate(key NodeKey, start time.Time, delay time.Duration, ts TimeSource) *TimerGate {
55 return &TimerGate{
56 BaseNode: BaseNode{Key: key, Label: "TimerGate", State: Pending},
57 StartTime: start,
58 Delay: delay,
59 time: ts,
60 }
61 }
62
63
64 func (g *TimerGate) Validate() error {
65 if g.GetKey() == "" {
66 return ErrInvalidGateState
67 }
68 return nil
69 }
70
71
72 func (g *TimerGate) IsOpen() bool {
73 now := g.time.Now()
74 openAt := g.StartTime.Add(g.Delay)
75
76 isTimeElapsed := now.After(openAt)
77 return isTimeElapsed
78 }
79
80
81 type ScheduleGate struct {
82 BaseNode `json:",inline"`
83
84
85 ScheduleTime time.Time
86
87
88
89 time TimeSource
90 }
91
92 func NewScheduleGate(key NodeKey, schedule time.Time, ts TimeSource) *ScheduleGate {
93 return &ScheduleGate{
94 BaseNode: BaseNode{Key: key, Label: "ScheduleGate", State: Pending},
95 ScheduleTime: schedule,
96 time: ts,
97 }
98 }
99
100
101 func (g *ScheduleGate) IsOpen() bool {
102 return time.Now().After(g.ScheduleTime)
103 }
104
105
106 type ApprovalGate struct {
107 BaseNode `json:",inline"`
108 GateState `json:"gate_state"`
109
110
111 }
112
113
114
115
116 type ApprovalSource func(context.Context) (bool, error)
117
118 func NewApprovalGate(key NodeKey) *ApprovalGate {
119 return &ApprovalGate{
120 BaseNode: BaseNode{Key: key, Label: "ApprovalGate", State: Pending},
121 GateState: Closed,
122 }
123 }
124
125 func (g *ApprovalGate) IsOpen() bool {
126 return bool(g.GateState)
127 }
128
View as plain text