controller-runtime icon indicating copy to clipboard operation
controller-runtime copied to clipboard

Predicate functions with side-effects versus pure functions

Open Miciah opened this issue 3 years ago • 0 comments

A colleague of mine wrote some controller code similar to the following:

  // New creates a new controller that updates metrics for Foo objects.
  func New(mgr manager.Manager, config Config) (controller.Controller, error) {
          reconciler := &reconciler{}
          c, err := controller.New(controllerName, mgr, controller.Options{Reconciler: reconciler})
          if err != nil {
                  return nil, err
          }
          if err := c.Watch(
                  &source.Kind{Type: &foov1.Foo{}},
                  handler.EnqueueRequestsFromMapFunc(func(client.Object) []reconcile.Request {
                          return nil
                  }),
                  predicate.Funcs{
                          CreateFunc: func(e event.CreateEvent) bool {
                                  if someCondition {
                                          someMetric.Inc()
                                  }
                                  return false
                          },
                          DeleteFunc: func(e event.DeleteEvent) bool {
                                  if someCondition {
                                          someMetric.Dec()
                                  }
                                  return false
                          },
                          UpdateFunc: func(e event.UpdateEvent) bool {
                                  if someCondition {
                                          someMetric.Inc()
                                  }
                                  if someOtherCondition {
                                          someMetric.Dec()
                                  }
                                  return false
                          },
                          GenericFunc: func(e event.GenericEvent) bool {
                                  return false
                          },
                  },
          ); err != nil {
                  return nil, err
          }
          return c, nil
  }

The intention is to perform some action (updating metrics) in the create/update/delete predicates on a watch, without enqueuing a reconciliation request. (This is convenient because the predicate function has the event type and other information, and presumably enqueueing a reconciliation request would incur more overhead than doing the work in the predicate.)

However, this raises the question: Does controller-runtime make any guarantees that exactly one predicate function will be called, and it will be called exactly once, for a given event, or is it assumed that predicates are pure functions? Are there caveats with defining and using predicates that have side-effects?

Would folks be open to updating the godoc for predicates to document any such guarantees, or the lack thereof, and any known caveats?

Miciah avatar Aug 03 '22 23:08 Miciah