sigs.k8s.io/kueue@v0.6.2/pkg/controller/core/leader_aware_reconciler.go (about) 1 /* 2 Copyright 2024 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package core 18 19 import ( 20 "context" 21 "time" 22 23 "k8s.io/utils/ptr" 24 ctrl "sigs.k8s.io/controller-runtime" 25 "sigs.k8s.io/controller-runtime/pkg/client" 26 "sigs.k8s.io/controller-runtime/pkg/reconcile" 27 28 config "sigs.k8s.io/kueue/apis/config/v1beta1" 29 ) 30 31 // WithLeadingManager returns a decorating reconcile.Reconciler that discards reconciliation requests 32 // for the controllers that are started with the controller.Options.NeedLeaderElection 33 // option set to false in non-leading replicas. 34 // 35 // Starting controllers in non-leading replicas is needed for these that update the data 36 // served by the visibility extension API server. 37 // 38 // This enables to: 39 // - Keep the scheduling decisions under the responsibility of the leading replica alone, 40 // to prevent any concurrency issues. 41 // - Consume requests from the watch event queues, to prevent them from growing indefinitely 42 // in the non-leading replicas. 43 // - Transition to actually reconciling requests in the replica that may acquire 44 // the leader election lease, in case the previously leading replica failed to renew it. 45 func WithLeadingManager(mgr ctrl.Manager, reconciler reconcile.Reconciler, obj client.Object, cfg *config.Configuration) reconcile.Reconciler { 46 // Do not decorate the reconciler if leader election is disabled 47 if cfg.LeaderElection == nil || !ptr.Deref(cfg.LeaderElection.LeaderElect, false) { 48 return reconciler 49 } 50 51 return &leaderAwareReconciler{ 52 elected: mgr.Elected(), 53 client: mgr.GetClient(), 54 delegate: reconciler, 55 object: obj, 56 requeueDuration: cfg.LeaderElection.LeaseDuration.Duration, 57 } 58 } 59 60 type leaderAwareReconciler struct { 61 elected <-chan struct{} 62 client client.Client 63 delegate reconcile.Reconciler 64 object client.Object 65 // the duration used by non-leading replicas to requeue events, 66 // so no events are missed over the period it takes for 67 // leader election to fail over a new replica. 68 requeueDuration time.Duration 69 } 70 71 var _ reconcile.Reconciler = (*leaderAwareReconciler)(nil) 72 73 func (r *leaderAwareReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { 74 select { 75 case <-r.elected: 76 // The manager has been elected leader, delegate reconciliation to the provided reconciler. 77 return r.delegate.Reconcile(ctx, request) 78 default: 79 if err := r.client.Get(ctx, request.NamespacedName, r.object); err != nil { 80 // Discard request if not found, to prevent from re-enqueueing indefinitely. 81 return ctrl.Result{}, client.IgnoreNotFound(err) 82 } 83 // The manager hasn't been elected leader yet, requeue the reconciliation request 84 // to prevent against any missed / discarded events over the period it takes 85 // to fail over a new leading replica, which can take as much as the configured 86 // lease duration, for it to acquire leadership. 87 return ctrl.Result{RequeueAfter: r.requeueDuration}, nil 88 } 89 }