@@ -107,14 +107,14 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
107
107
log := r .Log .WithValues ("cronjob" , req .NamespacedName )
108
108
109
109
/*
110
- ### 1: Load the named CronJob
110
+ ### 1: Load the named CronJob
111
111
112
- We'll fetch the CronJob using our client. All client methods take a context
113
- (to allow for cancellation) as their first argument, and the object in question
114
- as their last. Get is a bit special, in that it takes a [`NamespacedName`](../TODO.md)
115
- as the middle argument (most don't have a middle argument, as we'll see below).
112
+ We'll fetch the CronJob using our client. All client methods take a context
113
+ (to allow for cancellation) as their first argument, and the object in question
114
+ as their last. Get is a bit special, in that it takes a [`NamespacedName`](../TODO.md)
115
+ as the middle argument (most don't have a middle argument, as we'll see below).
116
116
117
- Many client methods also take variadic options at the end.
117
+ Many client methods also take variadic options at the end.
118
118
*/
119
119
var cronJob batch.CronJob
120
120
if err := r .Get (ctx , req .NamespacedName , & cronJob ); err != nil {
@@ -126,11 +126,11 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
126
126
}
127
127
128
128
/*
129
- ### 2: List all active jobs, and update the status
129
+ ### 2: List all active jobs, and update the status
130
130
131
- To fully update our status, we'll need to list all child jobs in this namespace that belong to this CronJob.
132
- Similarly to Get, we can use the List method to list the child jobs. Notice that we use variadic options to
133
- set the namespace and field match (which is actually an index lookup that we set up below).
131
+ To fully update our status, we'll need to list all child jobs in this namespace that belong to this CronJob.
132
+ Similarly to Get, we can use the List method to list the child jobs. Notice that we use variadic options to
133
+ set the namespace and field match (which is actually an index lookup that we set up below).
134
134
*/
135
135
var childJobs kbatch.JobList
136
136
if err := r .List (ctx , & childJobs , client .InNamespace (req .Namespace ), client .MatchingField (jobOwnerKey , req .Name )); err != nil {
@@ -139,15 +139,15 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
139
139
}
140
140
141
141
/*
142
- Once we have all the jobs we own, we'll split them into active, successful,
143
- and failed jobs, keeping track of the most recent run so that we can record it
144
- in status. Remember, status should be able to be reconstituted from the state
145
- of the world, so it's generally not a good idea to read from the status of the
146
- root object. Instead, you should reconstruct it every run. That's what we'll
147
- do here.
148
-
149
- We can check if a job is "finished" and whether is succeeded or failed using status
150
- conditions. We'll put that logic in a helper to make our code cleaner.
142
+ Once we have all the jobs we own, we'll split them into active, successful,
143
+ and failed jobs, keeping track of the most recent run so that we can record it
144
+ in status. Remember, status should be able to be reconstituted from the state
145
+ of the world, so it's generally not a good idea to read from the status of the
146
+ root object. Instead, you should reconstruct it every run. That's what we'll
147
+ do here.
148
+
149
+ We can check if a job is "finished" and whether is succeeded or failed using status
150
+ conditions. We'll put that logic in a helper to make our code cleaner.
151
151
*/
152
152
153
153
// find the active list of jobs
@@ -157,9 +157,9 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
157
157
var mostRecentTime * time.Time // find the last run so we can update the status
158
158
159
159
/*
160
- We consider a job "finished" if it has a "succeeded" or "failed" condition marked as true.
161
- Status conditions allow us to add extensible status information to our objects that other
162
- humans and controllers can examine to check things like completion and health.
160
+ We consider a job "finished" if it has a "succeeded" or "failed" condition marked as true.
161
+ Status conditions allow us to add extensible status information to our objects that other
162
+ humans and controllers can examine to check things like completion and health.
163
163
*/
164
164
isJobFinished := func (job * kbatch.Job ) (bool , kbatch.JobConditionType ) {
165
165
for _ , c := range job .Status .Conditions {
@@ -173,8 +173,8 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
173
173
// +kubebuilder:docs-gen:collapse=isJobFinished
174
174
175
175
/*
176
- We'll use a helper to extract the scheduled time from the annotation that
177
- we added during job creation.
176
+ We'll use a helper to extract the scheduled time from the annotation that
177
+ we added during job creation.
178
178
*/
179
179
getScheduledTimeForJob := func (job * kbatch.Job ) (* time.Time , error ) {
180
180
timeRaw := job .Annotations [scheduledTimeAnnotation ]
@@ -233,35 +233,35 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
233
233
}
234
234
235
235
/*
236
- Here, we'll log how many jobs we observed at a slightly higher logging level,
237
- for debugging. Notice how instead of using a format string, we use a fixed message,
238
- and attach key-value pairs with the extra information. This makes it easier to
239
- filter and query log lines.
236
+ Here, we'll log how many jobs we observed at a slightly higher logging level,
237
+ for debugging. Notice how instead of using a format string, we use a fixed message,
238
+ and attach key-value pairs with the extra information. This makes it easier to
239
+ filter and query log lines.
240
240
*/
241
241
log .V (1 ).Info ("job count" , "active jobs" , len (activeJobs ), "successful jobs" , len (successfulJobs ), "failed jobs" , len (failedJobs ))
242
242
243
243
/*
244
- Using the date we've gathered, we'll update the status of our CRD.
245
- Just like before, we use our client. To specifically update the status
246
- subresource, we'll use the the `Status` part of the client, with the `Update`
247
- method.
244
+ Using the date we've gathered, we'll update the status of our CRD.
245
+ Just like before, we use our client. To specifically update the status
246
+ subresource, we'll use the the `Status` part of the client, with the `Update`
247
+ method.
248
248
249
- The status subresource ignores changes to spec, so it's less likely to conflict
250
- with any other updates, and can have separate permissions.
249
+ The status subresource ignores changes to spec, so it's less likely to conflict
250
+ with any other updates, and can have separate permissions.
251
251
*/
252
252
if err := r .Status ().Update (ctx , & cronJob ); err != nil {
253
253
log .Error (err , "unable to update CronJob status" )
254
254
return ctrl.Result {}, err
255
255
}
256
256
257
257
/*
258
- Once we've updated our status, we can move on to ensuring that the status of
259
- the world matches what we want in our spec.
258
+ Once we've updated our status, we can move on to ensuring that the status of
259
+ the world matches what we want in our spec.
260
260
261
- ### 3: Clean up old jobs according to the history limit
261
+ ### 3: Clean up old jobs according to the history limit
262
262
263
- First, we'll try to clean up old jobs, so that we don't leave too many lying
264
- around.
263
+ First, we'll try to clean up old jobs, so that we don't leave too many lying
264
+ around.
265
265
*/
266
266
267
267
// NB: deleting these is "best effort" -- if we fail on a particular one,
@@ -313,22 +313,22 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
313
313
}
314
314
315
315
/*
316
- ### 5: Get the next scheduled run
316
+ ### 5: Get the next scheduled run
317
317
318
- If we're not pause, we'll need to calculate the next scheduled run, and whether
319
- or not we've got a run that we haven't processed yet.
318
+ If we're not pause, we'll need to calculate the next scheduled run, and whether
319
+ or not we've got a run that we haven't processed yet.
320
320
*/
321
321
322
322
/*
323
- We'll calculate the next scheduled time using our helpful cron library.
324
- We'll start calculating appropriate times from our last run, or the creation
325
- of the CronJob if we can't find a last run.
323
+ We'll calculate the next scheduled time using our helpful cron library.
324
+ We'll start calculating appropriate times from our last run, or the creation
325
+ of the CronJob if we can't find a last run.
326
326
327
- If there are too many missed runs and we don't have any deadlines set, we'll
328
- bail so that we don't cause issues on controller restarts or wedges.
327
+ If there are too many missed runs and we don't have any deadlines set, we'll
328
+ bail so that we don't cause issues on controller restarts or wedges.
329
329
330
- Otherwise, we'll just return the missed runs (of which we'll just use the latest),
331
- and the next run, so that we can know the latest time to reconcile again.
330
+ Otherwise, we'll just return the missed runs (of which we'll just use the latest),
331
+ and the next run, so that we can know the latest time to reconcile again.
332
332
*/
333
333
getNextSchedule := func (cronJob * batch.CronJob , now time.Time ) (lastMissed * time.Time , next time.Time , err error ) {
334
334
sched , err := cron .ParseStandard (cronJob .Spec .Schedule )
@@ -395,16 +395,16 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
395
395
}
396
396
397
397
/*
398
- We'll prep our eventual request to requeue until the next job, and then figure
399
- out if we actually need to run.
398
+ We'll prep our eventual request to requeue until the next job, and then figure
399
+ out if we actually need to run.
400
400
*/
401
401
scheduledResult := ctrl.Result {RequeueAfter : nextRun .Sub (r .Now ())} // save this so we can re-use it elsewhere
402
402
log = log .WithValues ("now" , r .Now (), "next run" , nextRun )
403
403
404
404
/*
405
- ### 6: Run a new job if it's on schedule, not past the deadline, and not blocked by our concurrency policy
405
+ ### 6: Run a new job if it's on schedule, not past the deadline, and not blocked by our concurrency policy
406
406
407
- If we've missed a run, and we're still within the deadline to start it, we'll need to run a job.
407
+ If we've missed a run, and we're still within the deadline to start it, we'll need to run a job.
408
408
*/
409
409
if missedRun == nil {
410
410
log .V (1 ).Info ("no upcoming scheduled times, sleeping until next" )
@@ -424,9 +424,9 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
424
424
}
425
425
426
426
/*
427
- If we actually have to run a job, we'll need to either wait till existing ones finish,
428
- replace the existing ones, or just add new ones. If our information is out of date due
429
- to cache delay, we'll get a requeue when we get up-to-date information.
427
+ If we actually have to run a job, we'll need to either wait till existing ones finish,
428
+ replace the existing ones, or just add new ones. If our information is out of date due
429
+ to cache delay, we'll get a requeue when we get up-to-date information.
430
430
*/
431
431
// figure out how to run this job -- concurrency policy might forbid us from running
432
432
// multiple at the same time...
@@ -451,15 +451,15 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
451
451
*/
452
452
453
453
/*
454
- We need to construct a job based on our CronJob's template. We'll copy over the spec
455
- from the template and copy some basic object meta.
454
+ We need to construct a job based on our CronJob's template. We'll copy over the spec
455
+ from the template and copy some basic object meta.
456
456
457
- Then, we'll set the "scheduled time" annotation so that we can reconstitute our
458
- `LastScheduleTime` field each reconcile.
457
+ Then, we'll set the "scheduled time" annotation so that we can reconstitute our
458
+ `LastScheduleTime` field each reconcile.
459
459
460
- Finally, we'll need to set an owner reference. This allows the Kubernetes garbage collector
461
- to clean up jobs when we delete the CronJob, and allows controller-runtime to figure out
462
- which cronjob needs to be reconciled when a given job changes (is added, deleted, completes, etc).
460
+ Finally, we'll need to set an owner reference. This allows the Kubernetes garbage collector
461
+ to clean up jobs when we delete the CronJob, and allows controller-runtime to figure out
462
+ which cronjob needs to be reconciled when a given job changes (is added, deleted, completes, etc).
463
463
*/
464
464
constructJobForCronJob := func (cronJob * batch.CronJob , scheduledTime time.Time ) (* kbatch.Job , error ) {
465
465
// We want job names for a given nominal start time to have a deterministic name to avoid the same job being created twice
@@ -506,12 +506,12 @@ func (r *CronJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
506
506
log .V (1 ).Info ("created Job for CronJob run" , "job" , job )
507
507
508
508
/*
509
- ### 7: Requeue when we either see a running job or it's time for the next scheduled run
509
+ ### 7: Requeue when we either see a running job or it's time for the next scheduled run
510
510
511
- Finally, we'll return the result that we prepped above, that says we want to requue
512
- when our next run would need to occur. This is taken as a maximum deadline -- if something
513
- else changes in between, like our job starts or finishes, we get modified, etc, we might
514
- reconcile again sooner.
511
+ Finally, we'll return the result that we prepped above, that says we want to requue
512
+ when our next run would need to occur. This is taken as a maximum deadline -- if something
513
+ else changes in between, like our job starts or finishes, we get modified, etc, we might
514
+ reconcile again sooner.
515
515
*/
516
516
// we'll requeue once we see the running job, and update our status
517
517
return scheduledResult , nil
0 commit comments