@@ -26,23 +26,38 @@ type Controller struct {
26
26
27
27
scheduler * cron.Cron
28
28
29
+ jobs chan struct {}
29
30
runningJobs sync.WaitGroup
30
31
}
31
32
32
33
func (c * Controller ) Start () error {
33
34
log .Info ("Starting usage controller." )
35
+ // Using channel of size 1 ensures we don't queue up overly many runs when there is already 1 queued up.
36
+ c .jobs = make (chan struct {}, 1 )
37
+
38
+ go func () {
39
+ // Here, we guarantee we're only ever executing 1 job at a time - in other words we always wait for the previous job to finish.
40
+ for range c .jobs {
41
+ c .runningJobs .Add (1 )
42
+ defer c .runningJobs .Done ()
43
+
44
+ err := c .reconciler .Reconcile ()
45
+ if err != nil {
46
+ log .WithError (err ).Errorf ("Reconciliation run failed." )
47
+ } else {
48
+ log .Info ("Completed usage reconciliation run without errors." )
49
+ }
50
+ }
51
+ }()
34
52
35
53
err := c .scheduler .AddFunc (fmt .Sprintf ("@every %s" , c .schedule .String ()), cron .FuncJob (func () {
36
54
log .Info ("Starting usage reconciliation." )
37
55
38
- c .runningJobs .Add (1 )
39
- defer c .runningJobs .Done ()
40
-
41
- err := c .reconciler .Reconcile ()
42
- if err != nil {
43
- log .WithError (err ).Errorf ("Reconciliation run failed." )
44
- } else {
45
- log .Info ("Completed usage reconciliation run without errors." )
56
+ select {
57
+ case c .jobs <- struct {}{}:
58
+ log .Info ("Triggered next reconciliation." )
59
+ default :
60
+ log .Info ("Previous reconciliation loop is still running, skipping." )
46
61
}
47
62
}))
48
63
if err != nil {
@@ -60,7 +75,10 @@ func (c *Controller) Stop() {
60
75
// Stop any new jobs from running
61
76
c .scheduler .Stop ()
62
77
78
+ close (c .jobs )
79
+
63
80
log .Info ("Awaiting existing reconciliation runs to complete.." )
64
81
// Wait for existing jobs to finish
65
82
c .runningJobs .Wait ()
83
+
66
84
}
0 commit comments