@@ -61,6 +61,7 @@ func ReconcilerConfigFromEnv() ReconcilerConfig {
6161type reconciler struct {
6262 kargoClient client.Client
6363 promoEngine promotion.Engine
64+ apiReader client.Reader
6465 shardPredicate controller.ResponsibleFor [kargoapi.Promotion ]
6566
6667 cfg ReconcilerConfig
@@ -116,6 +117,7 @@ func SetupReconcilerWithManager(
116117
117118 reconciler := newReconciler (
118119 kargoMgr .GetClient (),
120+ kargoMgr .GetAPIReader (),
119121 k8sevent .NewEventSender (
120122 libEvent .NewRecorder (ctx , kargoMgr .GetScheme (), kargoMgr .GetClient (), cfg .Name ()),
121123 ),
@@ -188,12 +190,14 @@ func SetupReconcilerWithManager(
188190
189191func newReconciler (
190192 kargoClient client.Client ,
193+ apiReader client.Reader ,
191194 sender event.Sender ,
192195 promoEngine promotion.Engine ,
193196 cfg ReconcilerConfig ,
194197) * reconciler {
195198 r := & reconciler {
196199 kargoClient : kargoClient ,
200+ apiReader : apiReader ,
197201 promoEngine : promoEngine ,
198202 sender : sender ,
199203 cfg : cfg ,
@@ -221,11 +225,15 @@ func (r *reconciler) Reconcile(
221225 ctx = logging .ContextWithLogger (ctx , logger )
222226 logger .Debug ("reconciling Promotion" )
223227
224- // Find the Promotion
225- promo , err := api .GetPromotion (ctx , r .kargoClient , req .NamespacedName )
226- if err != nil {
227- return ctrl.Result {}, err
228+ // Use direct API read to ensure we see the latest status.
229+ // This avoids a race condition where the cache hasn't yet reflected
230+ // a recently-patched status, causing promotions to error out if the informer cache is stale.
231+
232+ promo := & kargoapi.Promotion {}
233+ if err := r .apiReader .Get (ctx , req .NamespacedName , promo ); err != nil {
234+ return ctrl.Result {}, client .IgnoreNotFound (err )
228235 }
236+
229237 if promo == nil || promo .Status .Phase .IsTerminal () {
230238 // Ignore if not found or already finished. Promo might be nil if the
231239 // Promotion was deleted after the current reconciliation request was issued.
0 commit comments