@@ -9,9 +9,12 @@ description: >
99
1010Dependent objects are - by definition - the resources returned by the ` Generate() ` method of the used resource generator.
1111Whenever a component resource (that is, an instance of the component's custom resource type) is created, udpated, or deleted,
12- the set of dependent object probably changes, and the cluster state has to be synchronized with that new declared state.
12+ the set of dependent object potentially changes, and the cluster state has to be synchronized with that new declared state.
13+ This synchronization is the job of the reconciler provided by this framework.
1314
14- This is the job of the reconciler which is instantiated by calling the following constructor:
15+ ## Creating the reconciler instance
16+
17+ Typically, a component operator runs one reconciler which is instantiated by calling the following constructor:
1518
1619``` go
1720package component
@@ -28,13 +31,15 @@ func NewReconciler[T Component](
2831
2932The passed type parameter ` T Component ` is the concrete runtime type of the component's custom resource type. Furthermore,
3033- ` name ` is supposed to be a unique name (typically a DNS name) identifying this component operator in the cluster; ìt will be used in annotations, labels, for leader election, ...
31- - ` client ` , ` discoveryClient ` , ` eventRecorder ` and ` scheme ` are deprecated and will be removed in future releases; they can be passed as ` nil `
34+ - ` client ` , ` discoveryClient ` , ` eventRecorder ` and ` scheme ` are ignored and will be removed in future releases; they can be passed as ` nil `
3235- ` resourceGenerator ` is an implementation of the ` Generator ` interface, describing how the dependent objects are rendered from the component's spec.
3336
3437The object returned by ` NewReconciler ` implements controller-runtime's ` Reconciler ` interface, and can therefore be used as a drop-in
3538in kubebuilder managed projects. After creation, the reconciler has to be registered with the responsible controller-runtime manager instance by calling
3639
3740``` go
41+ package component
42+
3843func (r *Reconciler [T ]) SetupWithManager (mgr ctrl .Manager ) error
3944```
4045
@@ -47,4 +52,102 @@ The used manager `mgr` has to fulfill a few requirements:
4752 - the types in the API group defined in this repository
4853 - the core group (`v1`)
4954 - group `apiextensions.k8s.io/v1`
50- - group `apiregistration.k8s.io/v1`.
55+ - group `apiregistration.k8s.io/v1`.
56+
57+ ## Reconciler hooks
58+
59+ Component operators may register hooks to enhance the reconciler logic at certain points, by passing functions of type
60+
61+ ```go
62+ package component
63+
64+ // HookFunc is the function signature that can be used to
65+ // establish callbacks at certain points in the reconciliation logic.
66+ // Hooks will be passed the current (potentially unsaved) state of the component.
67+ // Post-hooks will only be called if the according operation (read, reconcile, delete)
68+ // has been successful.
69+ type HookFunc[T Component] func(ctx context.Context, client client.Client, component T) error
70+ ```
71+
72+ to the desired registration functions:
73+
74+ ```go
75+ package component
76+
77+ // Register post-read hook with reconciler.
78+ // This hook will be called after the reconciled component object has been retrieved from the Kubernetes API.
79+ func (r *Reconciler[T]) WithPostReadHook(hook HookFunc[T]) *Reconciler[T]
80+
81+ // Register pre-reconcile hook with reconciler.
82+ // This hook will be called if the reconciled component is not in deletion (has no deletionTimestamp set),
83+ // right before the reconcilation of the dependent objects starts.
84+ func (r *Reconciler[T]) WithPreReconcileHook(hook HookFunc[T]) *Reconciler[T]
85+
86+ // Register post-reconcile hook with reconciler.
87+ // This hook will be called if the reconciled component is not in deletion (has no deletionTimestamp set),
88+ // right after the reconcilation of the dependent objects happened, and was successful.
89+ func (r *Reconciler[T]) WithPostReconcileHook(hook HookFunc[T]) *Reconciler[T]
90+
91+ // Register pre-delete hook with reconciler.
92+ // This hook will be called if the reconciled component is in deletion (has a deletionTimestamp set),
93+ // right before the deletion of the dependent objects starts.
94+ func (r *Reconciler[T]) WithPreDeleteHook(hook HookFunc[T]) *Reconciler[T]
95+
96+ // Register post-delete hook with reconciler.
97+ // This hook will be called if the reconciled component is in deletion (has a deletionTimestamp set),
98+ // right after the deletion of the dependent objects happened, and was successful.
99+ func (r *Reconciler[T]) WithPostDeleteHook(hook HookFunc[T]) *Reconciler[T]
100+ ```
101+
102+ Note that the client passed to the hook functions is the client of the manager that was used when calling `SetupWithManager()`
103+ (that is, the return value of that manager's `GetClient()` method).
104+
105+ ## Tuning the retry behavior
106+
107+ By default, errors returned by the component's generator or by a registered hook will make the reconciler go
108+ into a backoff managed by controller-runtime (which usually is an exponential backoff, capped at 10 minutes).
109+ However, if the error is or unwraps to a `types.RetriableError`, then the retry delay specified at the error
110+ will be used instead of the backoff. Implementations should use
111+
112+ ```go
113+ pacakge types
114+
115+ func NewRetriableError(err error, retryAfter *time.Duration) RetriableError {
116+ return RetriableError{err: err, retryAfter: retryAfter}
117+ }
118+ ```
119+
120+ to wrap an error into a ` RetriableError ` . It is allowed to pass ` retryAfter ` as nil; in that case the retry delay
121+ will be determined by calling the component's ` GetRetryInterval() ` method (if the component or its spec implements
122+ the
123+
124+ ``` go
125+ package component
126+
127+ // The RetryConfiguration interface is meant to be implemented by components (or their spec) which offer
128+ // tweaking the retry interval (by default, it would be the value of the requeue interval).
129+ type RetryConfiguration interface {
130+ // Get retry interval. Should be greater than 1 minute.
131+ GetRetryInterval () time.Duration
132+ }
133+ ```
134+
135+ interface), or otherwise will be set to the effective requeue interval (see below).
136+
137+ ## Tuning the requeue behavior
138+
139+ If a component was successfully reconciled, another reconciliation will be scheduled after 10 minutes, by default.
140+ This default requeue interval may be overridden by the component by implementing the
141+
142+ ``` go
143+ package component
144+
145+ // The RequeueConfiguration interface is meant to be implemented by components (or their spec) which offer
146+ // tweaking the requeue interval (by default, it would be 10 minutes).
147+ type RequeueConfiguration interface {
148+ // Get requeue interval. Should be greater than 1 minute.
149+ GetRequeueInterval () time.Duration
150+ }
151+ ```
152+
153+ interface.
0 commit comments