@@ -21,7 +21,7 @@ import (
2121func (r * SeiNodeDeploymentReconciler ) reconcilePlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment , statusBase client.Patch ) (ctrl.Result , error ) {
2222 // Drive active plan.
2323 if group .Status .Plan != nil && group .Status .Plan .Phase == seiv1alpha1 .TaskPlanActive {
24- return r .drivePlan (ctx , group , statusBase )
24+ return r .drivePlan (ctx , group )
2525 }
2626
2727 // No active plan — ask the planner if one is needed.
@@ -38,17 +38,17 @@ func (r *SeiNodeDeploymentReconciler) reconcilePlan(ctx context.Context, group *
3838 return r .startPlan (ctx , group , statusBase , plan )
3939}
4040
41- func (r * SeiNodeDeploymentReconciler ) drivePlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment , statusBase client. Patch ) (ctrl.Result , error ) {
41+ func (r * SeiNodeDeploymentReconciler ) drivePlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment ) (ctrl.Result , error ) {
4242 result , err := r .PlanExecutor .ExecutePlan (ctx , group , group .Status .Plan )
4343 if err != nil {
4444 return result , err
4545 }
4646
4747 switch group .Status .Plan .Phase {
4848 case seiv1alpha1 .TaskPlanComplete :
49- return r .completePlan (ctx , group , statusBase )
49+ return r .completePlan (ctx , group )
5050 case seiv1alpha1 .TaskPlanFailed :
51- return r .failPlan (ctx , group , statusBase )
51+ return r .failPlan (ctx , group )
5252 }
5353
5454 return result , nil
@@ -70,9 +70,17 @@ func (r *SeiNodeDeploymentReconciler) startPlan(ctx context.Context, group *seiv
7070 return planner .ResultRequeueImmediate , nil
7171}
7272
73- func (r * SeiNodeDeploymentReconciler ) completePlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment , statusBase client. Patch ) (ctrl.Result , error ) {
73+ func (r * SeiNodeDeploymentReconciler ) completePlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment ) (ctrl.Result , error ) {
7474 logger := log .FromContext (ctx )
7575
76+ // Re-read to get a fresh resourceVersion. The plan executor patches
77+ // status mid-reconcile (task/plan completion), which invalidates the
78+ // statusBase computed at the start of Reconcile.
79+ if err := r .Get (ctx , client .ObjectKeyFromObject (group ), group ); err != nil {
80+ return ctrl.Result {}, fmt .Errorf ("re-reading group for completePlan: %w" , err )
81+ }
82+ status := client .MergeFromWithOptions (group .DeepCopy (), client.MergeFromWithOptimisticLock {})
83+
7684 isDeploymentPlan := group .Status .Rollout != nil
7785
7886 if isDeploymentPlan {
@@ -97,15 +105,20 @@ func (r *SeiNodeDeploymentReconciler) completePlan(ctx context.Context, group *s
97105 r .Recorder .Event (group , corev1 .EventTypeNormal , "PlanComplete" , "Plan completed successfully" )
98106 logger .Info ("plan completed" )
99107
100- if err := r .updateStatus (ctx , group , statusBase ); err != nil {
108+ if err := r .updateStatus (ctx , group , status ); err != nil {
101109 return ctrl.Result {}, fmt .Errorf ("updating status after plan completion: %w" , err )
102110 }
103111 return planner .ResultRequeueImmediate , nil
104112}
105113
106- func (r * SeiNodeDeploymentReconciler ) failPlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment , statusBase client. Patch ) (ctrl.Result , error ) {
114+ func (r * SeiNodeDeploymentReconciler ) failPlan (ctx context.Context , group * seiv1alpha1.SeiNodeDeployment ) (ctrl.Result , error ) {
107115 logger := log .FromContext (ctx )
108116
117+ if err := r .Get (ctx , client .ObjectKeyFromObject (group ), group ); err != nil {
118+ return ctrl.Result {}, fmt .Errorf ("re-reading group for failPlan: %w" , err )
119+ }
120+ status := client .MergeFromWithOptions (group .DeepCopy (), client.MergeFromWithOptimisticLock {})
121+
109122 group .Status .Phase = seiv1alpha1 .GroupPhaseDegraded
110123 group .Status .Plan = nil
111124 if group .Status .Rollout != nil {
@@ -118,7 +131,7 @@ func (r *SeiNodeDeploymentReconciler) failPlan(ctx context.Context, group *seiv1
118131 r .Recorder .Event (group , corev1 .EventTypeWarning , "PlanFailed" , "Plan failed" )
119132 logger .Info ("plan failed" )
120133
121- if err := r .updateStatus (ctx , group , statusBase ); err != nil {
134+ if err := r .updateStatus (ctx , group , status ); err != nil {
122135 return ctrl.Result {}, fmt .Errorf ("updating status after plan failure: %w" , err )
123136 }
124137 return planner .ResultRequeueImmediate , nil
0 commit comments