reconciler
About 355 words
Enforces Kubernetes reconciler best practices.
Category
Kubernetes
What It Checks
This analyzer checks the Reconcile methods of types named like a Reconciler, Controller or Operator:
- the signature is
(ctx context.Context, req reconcile.Request) (reconcile.Result, error) - a method that calls
client.Getalso handles not-found errors, withapierrors.IsNotFoundorclient.IgnoreNotFound, so a deleted object doesn't requeue - no direct HTTP calls (
net/httpfunctions andhttp.Clientmethods, wherever the client comes from) or database calls (database/sql,sqlx,pgx) - no locking of a package-level mutex, which shares state across concurrent reconciles; a mutex in a field of the reconciler is fine
- no
time.Sleep(useRequeueAfter), and a hint to inject a clock fortime.Now - structured logging instead of
fmt.Print*andlog.Print*
Why It Matters
Reconcilers have subtle requirements. Incorrect patterns cause:
- Infinite reconcile loops
- Missed updates
- Resource leaks
- Controller crashes
Examples
Bad: Not Handling NotFound
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
obj := &myv1.MyResource{}
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
return ctrl.Result{}, err // Error logged for normal deletions!
}
// ...
}Good: Ignore NotFound
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
obj := &myv1.MyResource{}
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// ...
}Bad: Tight Requeue Loop
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// ... work ...
return ctrl.Result{Requeue: true}, nil // Tight loop, no backoff!
}Good: Explicit Backoff
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// ... work ...
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}Good: Let Controller-Runtime Handle Backoff
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// ... work ...
if err != nil {
return ctrl.Result{}, err // Exponential backoff on error
}
return ctrl.Result{}, nil // No requeue if successful
}Configuration
# .golint-sl.yaml
analyzers:
reconciler: true # enabled by defaultWhen to Disable
- Non-Kubernetes projects
- Projects not using controller-runtime
analyzers:
reconciler: falseRelated Analyzers
- statusupdate - Status update requirements
- sideeffects - Side effect detection
