@@ -17,7 +17,9 @@ import (
1717 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1818 "k8s.io/apimachinery/pkg/runtime"
1919 ctrl "sigs.k8s.io/controller-runtime"
20+ "sigs.k8s.io/controller-runtime/pkg/builder"
2021 "sigs.k8s.io/controller-runtime/pkg/client"
22+ "sigs.k8s.io/controller-runtime/pkg/controller"
2123 "sigs.k8s.io/controller-runtime/pkg/predicate"
2224)
2325
@@ -27,33 +29,37 @@ var apiGVStr = lighthousev1alpha1.SchemeGroupVersion.String()
2729
2830// LighthouseJobReconciler reconciles a LighthouseJob object
2931type LighthouseJobReconciler struct {
30- client client.Client
31- tektonclient tektonversioned.Interface
32- apiReader client.Reader
33- logger * logrus.Entry
34- scheme * runtime.Scheme
35- idGenerator buildIDGenerator
36- dashboardURL string
37- dashboardTemplate string
38- namespace string
39- disableLogging bool
32+ client client.Client
33+ tektonclient tektonversioned.Interface
34+ apiReader client.Reader
35+ logger * logrus.Entry
36+ scheme * runtime.Scheme
37+ idGenerator buildIDGenerator
38+ dashboardURL string
39+ dashboardTemplate string
40+ namespace string
41+ disableLogging bool
42+ skipTerminatedReconciles bool
43+ maxConcurrentReconciles int
4044}
4145
4246// NewLighthouseJobReconciler creates a LighthouseJob reconciler
43- func NewLighthouseJobReconciler (client client.Client , apiReader client.Reader , scheme * runtime.Scheme , tektonclient tektonversioned.Interface , dashboardURL string , dashboardTemplate string , namespace string ) * LighthouseJobReconciler {
47+ func NewLighthouseJobReconciler (client client.Client , apiReader client.Reader , scheme * runtime.Scheme , tektonclient tektonversioned.Interface , dashboardURL string , dashboardTemplate string , namespace string , skipTerminatedReconciles bool , maxConcurrentReconciles int ) * LighthouseJobReconciler {
4448 if dashboardTemplate == "" {
4549 dashboardTemplate = os .Getenv ("LIGHTHOUSE_DASHBOARD_TEMPLATE" )
4650 }
4751 return & LighthouseJobReconciler {
48- client : client ,
49- apiReader : apiReader ,
50- logger : logrus .NewEntry (logrus .StandardLogger ()).WithField ("controller" , controllerName ),
51- scheme : scheme ,
52- dashboardURL : dashboardURL ,
53- dashboardTemplate : dashboardTemplate ,
54- namespace : namespace ,
55- tektonclient : tektonclient ,
56- idGenerator : & epochBuildIDGenerator {},
52+ client : client ,
53+ apiReader : apiReader ,
54+ logger : logrus .NewEntry (logrus .StandardLogger ()).WithField ("controller" , controllerName ),
55+ scheme : scheme ,
56+ dashboardURL : dashboardURL ,
57+ dashboardTemplate : dashboardTemplate ,
58+ namespace : namespace ,
59+ tektonclient : tektonclient ,
60+ idGenerator : & epochBuildIDGenerator {},
61+ skipTerminatedReconciles : skipTerminatedReconciles ,
62+ maxConcurrentReconciles : maxConcurrentReconciles ,
5763 }
5864}
5965
@@ -74,11 +80,23 @@ func (r *LighthouseJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
7480 return err
7581 }
7682
77- return ctrl .NewControllerManagedBy (mgr ).
78- For (& lighthousev1alpha1.LighthouseJob {}).
79- WithEventFilter (predicate.ResourceVersionChangedPredicate {}).
80- Owns (& pipelinev1.PipelineRun {}).
81- Complete (r )
83+ ctrlr := ctrl .NewControllerManagedBy (mgr ).
84+ For (& lighthousev1alpha1.LighthouseJob {}, builder .WithPredicates (
85+ lighthouseJobPredicateFactory (r .skipTerminatedReconciles ),
86+ )).
87+ Owns (& pipelinev1.PipelineRun {}, builder .WithPredicates (
88+ predicate.ResourceVersionChangedPredicate {},
89+ ))
90+
91+ if r .maxConcurrentReconciles > 1 {
92+ ctrlr = ctrlr .WithOptions (
93+ controller.Options {
94+ MaxConcurrentReconciles : r .maxConcurrentReconciles ,
95+ },
96+ )
97+ }
98+
99+ return ctrlr .Complete (r )
82100}
83101
84102// Reconcile represents an iteration of the reconciliation loop
@@ -180,6 +198,19 @@ func (r *LighthouseJobReconciler) Reconcile(ctx context.Context, req ctrl.Reques
180198 }
181199 }
182200
201+ // When terminal shortcut is enabled, skip ConvertPipelineRun + status update if the PipelineRun is
202+ // done and Activity already matches (covers Owns(PipelineRun) events; same flag as For() predicate).
203+ if r .skipTerminatedReconciles {
204+ expectedReportURL := ""
205+ if r .dashboardURL != "" {
206+ expectedReportURL = r .getPipelingetPipelineTargetURLeTargetURL (pipelineRun )
207+ }
208+ if TerminalActivitySyncedWithPipelineRun (& job , & pipelineRun , expectedReportURL , r .dashboardURL != "" ) {
209+ r .logger .Debugf ("Skipping terminal in-sync LighthouseJob %s" , req .Name )
210+ return ctrl.Result {}, nil
211+ }
212+ }
213+
183214 f := func (job * lighthousev1alpha1.LighthouseJob ) error {
184215 if r .dashboardURL != "" {
185216 job .Status .ReportURL = r .getPipelingetPipelineTargetURLeTargetURL (pipelineRun )
@@ -271,3 +302,25 @@ func (r *LighthouseJobReconciler) retryModifyJob(ctx context.Context, ns client.
271302 }
272303 }
273304}
305+
306+ // lighthouseJobPredicateFactory returns the For(LighthouseJob) predicate set. When skipTerminatedReconciles
307+ // is false, only ResourceVersionChangedPredicate is used (legacy behavior). When true, it also skips
308+ // enqueue for LighthouseJobs whose activity is already in a terminal pipeline state (see Reconcile fast path).
309+ func lighthouseJobPredicateFactory (skipTerminatedReconciles bool ) predicate.Predicate {
310+ if skipTerminatedReconciles {
311+ return predicate .And (
312+ predicate.ResourceVersionChangedPredicate {},
313+ predicate .NewPredicateFuncs (func (object client.Object ) bool {
314+ job , ok := object .(* lighthousev1alpha1.LighthouseJob )
315+ if ! ok {
316+ return true
317+ }
318+ if job .Status .Activity != nil {
319+ return ! lighthousev1alpha1 .IsTerminalPipelineState (job .Status .Activity .Status )
320+ }
321+ return true
322+ }),
323+ )
324+ }
325+ return predicate.ResourceVersionChangedPredicate {}
326+ }
0 commit comments