github.com/crossplane/upjet@v1.3.0/pkg/controller/handler/eventhandler.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package handler
     6  
     7  import (
     8  	"context"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/crossplane/crossplane-runtime/pkg/logging"
    13  	"k8s.io/apimachinery/pkg/types"
    14  	"k8s.io/client-go/util/workqueue"
    15  	"sigs.k8s.io/controller-runtime/pkg/event"
    16  	"sigs.k8s.io/controller-runtime/pkg/handler"
    17  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    18  )
    19  
    20  const NoRateLimiter = ""
    21  
    22  // EventHandler handles Kubernetes events by queueing reconcile requests for
    23  // objects and allows upjet components to queue reconcile requests.
    24  type EventHandler struct {
    25  	innerHandler   handler.EventHandler
    26  	queue          workqueue.RateLimitingInterface
    27  	rateLimiterMap map[string]workqueue.RateLimiter
    28  	logger         logging.Logger
    29  	mu             *sync.RWMutex
    30  }
    31  
    32  // Option configures an option for the EventHandler.
    33  type Option func(eventHandler *EventHandler)
    34  
    35  // WithLogger configures the logger for the EventHandler.
    36  func WithLogger(logger logging.Logger) Option {
    37  	return func(eventHandler *EventHandler) {
    38  		eventHandler.logger = logger
    39  	}
    40  }
    41  
    42  // NewEventHandler initializes a new EventHandler instance.
    43  func NewEventHandler(opts ...Option) *EventHandler {
    44  	eh := &EventHandler{
    45  		innerHandler:   &handler.EnqueueRequestForObject{},
    46  		mu:             &sync.RWMutex{},
    47  		rateLimiterMap: make(map[string]workqueue.RateLimiter),
    48  	}
    49  	for _, o := range opts {
    50  		o(eh)
    51  	}
    52  	return eh
    53  }
    54  
    55  // RequestReconcile requeues a reconciliation request for the specified name.
    56  // Returns true if the reconcile request was successfully queued.
    57  func (e *EventHandler) RequestReconcile(rateLimiterName, name string, failureLimit *int) bool {
    58  	e.mu.Lock()
    59  	defer e.mu.Unlock()
    60  	if e.queue == nil {
    61  		return false
    62  	}
    63  	logger := e.logger.WithValues("name", name)
    64  	item := reconcile.Request{
    65  		NamespacedName: types.NamespacedName{
    66  			Name: name,
    67  		},
    68  	}
    69  	var when time.Duration = 0
    70  	if rateLimiterName != NoRateLimiter {
    71  		rateLimiter := e.rateLimiterMap[rateLimiterName]
    72  		if rateLimiter == nil {
    73  			rateLimiter = workqueue.DefaultControllerRateLimiter()
    74  			e.rateLimiterMap[rateLimiterName] = rateLimiter
    75  		}
    76  		if failureLimit != nil && rateLimiter.NumRequeues(item) > *failureLimit {
    77  			logger.Info("Failure limit has been exceeded.", "failureLimit", *failureLimit, "numRequeues", rateLimiter.NumRequeues(item))
    78  			return false
    79  		}
    80  		when = rateLimiter.When(item)
    81  	}
    82  	e.queue.AddAfter(item, when)
    83  	logger.Debug("Reconcile request has been requeued.", "rateLimiterName", rateLimiterName, "when", when)
    84  	return true
    85  }
    86  
    87  // Forget indicates that the reconcile retries is finished for
    88  // the specified name.
    89  func (e *EventHandler) Forget(rateLimiterName, name string) {
    90  	e.mu.RLock()
    91  	defer e.mu.RUnlock()
    92  	rateLimiter := e.rateLimiterMap[rateLimiterName]
    93  	if rateLimiter == nil {
    94  		return
    95  	}
    96  	rateLimiter.Forget(reconcile.Request{
    97  		NamespacedName: types.NamespacedName{
    98  			Name: name,
    99  		},
   100  	})
   101  }
   102  
   103  func (e *EventHandler) setQueue(limitingInterface workqueue.RateLimitingInterface) {
   104  	e.mu.Lock()
   105  	defer e.mu.Unlock()
   106  	if e.queue == nil {
   107  		e.queue = limitingInterface
   108  	}
   109  }
   110  
   111  func (e *EventHandler) Create(ctx context.Context, ev event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) {
   112  	e.setQueue(limitingInterface)
   113  	e.logger.Debug("Calling the inner handler for Create event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
   114  	e.innerHandler.Create(ctx, ev, limitingInterface)
   115  }
   116  
   117  func (e *EventHandler) Update(ctx context.Context, ev event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) {
   118  	e.setQueue(limitingInterface)
   119  	e.logger.Debug("Calling the inner handler for Update event.", "name", ev.ObjectOld.GetName(), "queueLength", limitingInterface.Len())
   120  	e.innerHandler.Update(ctx, ev, limitingInterface)
   121  }
   122  
   123  func (e *EventHandler) Delete(ctx context.Context, ev event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) {
   124  	e.setQueue(limitingInterface)
   125  	e.logger.Debug("Calling the inner handler for Delete event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
   126  	e.innerHandler.Delete(ctx, ev, limitingInterface)
   127  }
   128  
   129  func (e *EventHandler) Generic(ctx context.Context, ev event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
   130  	e.setQueue(limitingInterface)
   131  	e.logger.Debug("Calling the inner handler for Generic event.", "name", ev.Object.GetName(), "queueLength", limitingInterface.Len())
   132  	e.innerHandler.Generic(ctx, ev, limitingInterface)
   133  }