Skip to content

Commit 6724282

Browse files
authored
Merge pull request #3376 from sbueringer/pr-impl-syncperiod-cache-overwrite
✨ cache: Allow fine-granular SyncPeriod configuration
2 parents 100354a + 88b888d commit 6724282

File tree

2 files changed

+103
-5
lines changed

2 files changed

+103
-5
lines changed

pkg/cache/cache.go

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,42 @@ type ByObject struct {
307307
//
308308
// Defaults to true.
309309
EnableWatchBookmarks *bool
310+
311+
// SyncPeriod determines the minimum frequency at which watched resources are
312+
// reconciled. A lower period will correct entropy more quickly, but reduce
313+
// responsiveness to change if there are many watched resources. Change this
314+
// value only if you know what you are doing. Defaults to 10 hours if unset.
315+
// there will a 10 percent jitter between the SyncPeriod of all controllers
316+
// so that all controllers will not send list requests simultaneously.
317+
//
318+
// This applies to all controllers.
319+
//
320+
// A period sync happens for two reasons:
321+
// 1. To insure against a bug in the controller that causes an object to not
322+
// be requeued, when it otherwise should be requeued.
323+
// 2. To insure against an unknown bug in controller-runtime, or its dependencies,
324+
// that causes an object to not be requeued, when it otherwise should be
325+
// requeued, or to be removed from the queue, when it otherwise should not
326+
// be removed.
327+
//
328+
// If you want
329+
// 1. to insure against missed watch events, or
330+
// 2. to poll services that cannot be watched,
331+
// then we recommend that, instead of changing the default period, the
332+
// controller requeue, with a constant duration `t`, whenever the controller
333+
// is "done" with an object, and would otherwise not requeue it, i.e., we
334+
// recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
335+
// instead of `reconcile.Result{}`.
336+
//
337+
// SyncPeriod will locally trigger an artificial Update event with the same
338+
// object in both ObjectOld and ObjectNew for everything that is in the
339+
// cache.
340+
//
341+
// Predicates or Handlers that expect ObjectOld and ObjectNew to be different
342+
// (such as GenerationChangedPredicate) will filter out this event, preventing
343+
// it from triggering a reconciliation.
344+
// SyncPeriod does not sync between the local cache and the server.
345+
SyncPeriod *time.Duration
310346
}
311347

312348
// Config describes all potential options for a given watch.
@@ -342,6 +378,42 @@ type Config struct {
342378
//
343379
// Defaults to true.
344380
EnableWatchBookmarks *bool
381+
382+
// SyncPeriod determines the minimum frequency at which watched resources are
383+
// reconciled. A lower period will correct entropy more quickly, but reduce
384+
// responsiveness to change if there are many watched resources. Change this
385+
// value only if you know what you are doing. Defaults to 10 hours if unset.
386+
// there will a 10 percent jitter between the SyncPeriod of all controllers
387+
// so that all controllers will not send list requests simultaneously.
388+
//
389+
// This applies to all controllers.
390+
//
391+
// A period sync happens for two reasons:
392+
// 1. To insure against a bug in the controller that causes an object to not
393+
// be requeued, when it otherwise should be requeued.
394+
// 2. To insure against an unknown bug in controller-runtime, or its dependencies,
395+
// that causes an object to not be requeued, when it otherwise should be
396+
// requeued, or to be removed from the queue, when it otherwise should not
397+
// be removed.
398+
//
399+
// If you want
400+
// 1. to insure against missed watch events, or
401+
// 2. to poll services that cannot be watched,
402+
// then we recommend that, instead of changing the default period, the
403+
// controller requeue, with a constant duration `t`, whenever the controller
404+
// is "done" with an object, and would otherwise not requeue it, i.e., we
405+
// recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
406+
// instead of `reconcile.Result{}`.
407+
//
408+
// SyncPeriod will locally trigger an artificial Update event with the same
409+
// object in both ObjectOld and ObjectNew for everything that is in the
410+
// cache.
411+
//
412+
// Predicates or Handlers that expect ObjectOld and ObjectNew to be different
413+
// (such as GenerationChangedPredicate) will filter out this event, preventing
414+
// it from triggering a reconciliation.
415+
// SyncPeriod does not sync between the local cache and the server.
416+
SyncPeriod *time.Duration
345417
}
346418

347419
// NewCacheFunc - Function for creating a new cache from the options and a rest config.
@@ -412,6 +484,7 @@ func optionDefaultsToConfig(opts *Options) Config {
412484
Transform: opts.DefaultTransform,
413485
UnsafeDisableDeepCopy: opts.DefaultUnsafeDisableDeepCopy,
414486
EnableWatchBookmarks: opts.DefaultEnableWatchBookmarks,
487+
SyncPeriod: opts.SyncPeriod,
415488
}
416489
}
417490

@@ -422,6 +495,7 @@ func byObjectToConfig(byObject ByObject) Config {
422495
Transform: byObject.Transform,
423496
UnsafeDisableDeepCopy: byObject.UnsafeDisableDeepCopy,
424497
EnableWatchBookmarks: byObject.EnableWatchBookmarks,
498+
SyncPeriod: byObject.SyncPeriod,
425499
}
426500
}
427501

@@ -435,7 +509,7 @@ func newCache(restConfig *rest.Config, opts Options) newCacheFunc {
435509
HTTPClient: opts.HTTPClient,
436510
Scheme: opts.Scheme,
437511
Mapper: opts.Mapper,
438-
ResyncPeriod: *opts.SyncPeriod,
512+
ResyncPeriod: ptr.Deref(config.SyncPeriod, defaultSyncPeriod),
439513
Namespace: namespace,
440514
Selector: internal.Selector{
441515
Label: config.LabelSelector,
@@ -533,6 +607,7 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
533607
byObject.Transform = defaultedConfig.Transform
534608
byObject.UnsafeDisableDeepCopy = defaultedConfig.UnsafeDisableDeepCopy
535609
byObject.EnableWatchBookmarks = defaultedConfig.EnableWatchBookmarks
610+
byObject.SyncPeriod = defaultedConfig.SyncPeriod
536611
}
537612

538613
opts.ByObject[obj] = byObject
@@ -554,10 +629,6 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
554629
opts.DefaultNamespaces[namespace] = cfg
555630
}
556631

557-
// Default the resync period to 10 hours if unset
558-
if opts.SyncPeriod == nil {
559-
opts.SyncPeriod = &defaultSyncPeriod
560-
}
561632
return opts, nil
562633
}
563634

@@ -577,6 +648,9 @@ func defaultConfig(toDefault, defaultFrom Config) Config {
577648
if toDefault.EnableWatchBookmarks == nil {
578649
toDefault.EnableWatchBookmarks = defaultFrom.EnableWatchBookmarks
579650
}
651+
if toDefault.SyncPeriod == nil {
652+
toDefault.SyncPeriod = defaultFrom.SyncPeriod
653+
}
580654
return toDefault
581655
}
582656

pkg/cache/defaulting_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,30 @@ func TestDefaultOpts(t *testing.T) {
249249
return cmp.Diff(expected, o.ByObject[pod].EnableWatchBookmarks)
250250
},
251251
},
252+
{
253+
name: "ByObject.SyncPeriod gets defaulted from SyncPeriod",
254+
in: Options{
255+
ByObject: map[client.Object]ByObject{pod: {}},
256+
SyncPeriod: ptr.To(5 * time.Minute),
257+
},
258+
259+
verification: func(o Options) string {
260+
expected := ptr.To(5 * time.Minute)
261+
return cmp.Diff(expected, o.ByObject[pod].SyncPeriod)
262+
},
263+
},
264+
{
265+
name: "ByObject.SyncPeriod doesn't get defaulted when set",
266+
in: Options{
267+
ByObject: map[client.Object]ByObject{pod: {SyncPeriod: ptr.To(1 * time.Minute)}},
268+
SyncPeriod: ptr.To(5 * time.Minute),
269+
},
270+
271+
verification: func(o Options) string {
272+
expected := ptr.To(1 * time.Minute)
273+
return cmp.Diff(expected, o.ByObject[pod].SyncPeriod)
274+
},
275+
},
252276
{
253277
name: "DefaultNamespace label selector gets defaulted from DefaultLabelSelector",
254278
in: Options{

0 commit comments

Comments
 (0)