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 }