@@ -38,6 +38,7 @@ type StoreReconciler struct {
38
38
clock quartz.Clock
39
39
40
40
cancelFn context.CancelCauseFunc
41
+ running atomic.Bool
41
42
stopped atomic.Bool
42
43
done chan struct {}
43
44
}
@@ -61,7 +62,7 @@ func NewStoreReconciler(
61
62
}
62
63
}
63
64
64
- func (c * StoreReconciler ) RunLoop (ctx context.Context ) {
65
+ func (c * StoreReconciler ) Run (ctx context.Context ) {
65
66
reconciliationInterval := c .cfg .ReconciliationInterval .Value ()
66
67
if reconciliationInterval <= 0 { // avoids a panic
67
68
reconciliationInterval = 5 * time .Minute
@@ -82,6 +83,11 @@ func (c *StoreReconciler) RunLoop(ctx context.Context) {
82
83
ctx , cancel := context .WithCancelCause (dbauthz .AsPrebuildsOrchestrator (ctx ))
83
84
c .cancelFn = cancel
84
85
86
+ // Everything is in place, reconciler can now be considered as running.
87
+ //
88
+ // NOTE: without this atomic bool, Stop might race with Run for the c.cancelFn above.
89
+ c .running .Store (true )
90
+
85
91
for {
86
92
select {
87
93
// TODO: implement pubsub listener to allow reconciling a specific template imperatively once it has been changed,
@@ -107,16 +113,26 @@ func (c *StoreReconciler) RunLoop(ctx context.Context) {
107
113
}
108
114
109
115
func (c * StoreReconciler ) Stop (ctx context.Context , cause error ) {
116
+ defer c .running .Store (false )
117
+
110
118
if cause != nil {
111
119
c .logger .Error (context .Background (), "stopping reconciler due to an error" , slog .Error (cause ))
112
120
} else {
113
121
c .logger .Info (context .Background (), "gracefully stopping reconciler" )
114
122
}
115
123
116
- if c .isStopped () {
124
+ // If previously stopped (Swap returns previous value), then short-circuit.
125
+ //
126
+ // NOTE: we need to *prospectively* mark this as stopped to prevent Stop being called multiple times and causing problems.
127
+ if c .stopped .Swap (true ) {
128
+ return
129
+ }
130
+
131
+ // If the reconciler is not running, there's nothing else to do.
132
+ if ! c .running .Load () {
117
133
return
118
134
}
119
- c . stopped . Store ( true )
135
+
120
136
if c .cancelFn != nil {
121
137
c .cancelFn (cause )
122
138
}
@@ -138,10 +154,6 @@ func (c *StoreReconciler) Stop(ctx context.Context, cause error) {
138
154
}
139
155
}
140
156
141
- func (c * StoreReconciler ) isStopped () bool {
142
- return c .stopped .Load ()
143
- }
144
-
145
157
// ReconcileAll will attempt to resolve the desired vs actual state of all templates which have presets with prebuilds configured.
146
158
//
147
159
// NOTE:
0 commit comments