@@ -139,9 +139,10 @@ func (r *StormServiceReconciler) processCanaryUpdate(ctx context.Context, stormS
139139 currentStepIndex := canaryStatus .CurrentStep
140140 if currentStepIndex < int32 (len (steps )) {
141141 currentStep := steps [currentStepIndex ]
142- // If current step is a manual pause step but no pause condition exists, advance
142+ // Treat as resume ONLY if we've already marked PausedAt (i.e., entered this pause step)
143+ // and the CanaryPauseStep condition has been removed by the user.
143144 if currentStep .Pause != nil && currentStep .Pause .IsManualPause () {
144- if ! r .hasPauseCondition (canaryStatus , orchestrationv1alpha1 .PauseReasonCanaryPauseStep ) {
145+ if canaryStatus . PausedAt != nil && ! r .hasPauseCondition (canaryStatus , orchestrationv1alpha1 .PauseReasonCanaryPauseStep ) {
145146 klog .Infof ("Manual pause condition removed for StormService %s/%s, advancing to next step" ,
146147 stormService .Namespace , stormService .Name )
147148 return r .advanceCanaryStep (ctx , stormService )
@@ -211,7 +212,7 @@ func (r *StormServiceReconciler) processCanaryPauseStep(ctx context.Context, sto
211212 addStatusUpdate (func (status * orchestrationv1alpha1.CanaryStatus ) {
212213 status .PausedAt = & now
213214 status .Phase = orchestrationv1alpha1 .CanaryPhasePaused
214-
215+
215216 // Add pause condition to track why it's paused
216217 pauseCondition := orchestrationv1alpha1.PauseCondition {
217218 Reason : orchestrationv1alpha1 .PauseReasonCanaryPauseStep ,
@@ -297,8 +298,12 @@ func (r *StormServiceReconciler) processCanaryPauseStep(ctx context.Context, sto
297298 return ctrl.Result {}, fmt .Errorf ("failed to add CanaryPauseStep pause condition: %w" , err )
298299 }
299300 } else {
300- r .EventRecorder .Eventf (stormService , "Normal" , "CanaryPauseManual" ,
301- "Canary paused at manual pause step. Remove CanaryPauseStep pause condition to continue" )
301+ // Emit a consistent CanaryUpdate event even if the pause condition already exists
302+ update := newCanaryStatusUpdate ().
303+ addEvent ("Canary paused at manual pause step. Remove CanaryPauseStep pause condition to continue" )
304+ if err := r .applyCanaryStatusUpdate (ctx , stormService , update ); err != nil {
305+ return ctrl.Result {}, fmt .Errorf ("failed to record manual pause event: %w" , err )
306+ }
302307 }
303308
304309 // Requeue periodically to check if pause condition was removed
@@ -342,15 +347,15 @@ func (r *StormServiceReconciler) applyCanaryWeight(ctx context.Context, stormSer
342347
343348 // Check if this is a scaling event during canary (compare with current status replicas)
344349 currentStatusReplicas := stormService .Status .Replicas
345-
350+
346351 // If replicas changed during canary, log and notify but continue with recalculation
347352 if currentStatusReplicas > 0 && currentStatusReplicas != totalReplicas {
348- klog .Infof ("Scaling detected during canary for StormService %s/%s: %d -> %d replicas, recalculating distribution" ,
353+ klog .Infof ("Scaling detected during canary for StormService %s/%s: %d -> %d replicas, recalculating distribution" ,
349354 stormService .Namespace , stormService .Name , currentStatusReplicas , totalReplicas )
350-
355+
351356 // Log the recalculation event
352357 r .EventRecorder .Eventf (stormService , "Normal" , "CanaryScaling" ,
353- "Recalculated canary distribution due to scaling: %d%% weight with %d total replicas (%d canary, %d stable)" ,
358+ "Recalculated canary distribution due to scaling: %d%% weight with %d total replicas (%d canary, %d stable)" ,
354359 weight , totalReplicas , canaryReplicas , stableReplicas )
355360 }
356361
@@ -401,7 +406,7 @@ func (r *StormServiceReconciler) advanceCanaryStep(ctx context.Context, stormSer
401406 update := newCanaryStatusUpdate ().
402407 addStatusUpdate (func (status * orchestrationv1alpha1.CanaryStatus ) {
403408 status .CurrentStep = nextStep
404- status .PausedAt = nil // Clear pause timestamp
409+ status .PausedAt = nil // Clear pause timestamp
405410 status .PauseConditions = nil // Clear pause conditions when resuming
406411 status .Phase = orchestrationv1alpha1 .CanaryPhaseProgressing
407412 })
@@ -474,15 +479,17 @@ func (r *StormServiceReconciler) completeCanary(ctx context.Context, stormServic
474479 return ctrl.Result {}, fmt .Errorf ("failed to promote canary revision: %w" , err )
475480 }
476481
482+ // Use single patch operation for the final status update
483+ // Capture the original object BEFORE mutating status to ensure the patch contains the changes
484+ original := stormService .DeepCopy ()
485+
477486 // Step 3: Update main status to reflect the promotion
478487 stormService .Status .CurrentRevision = promotedRevision
479488 stormService .Status .UpdateRevision = promotedRevision
480489
481490 // Step 4: Clear canary status - this triggers normal rollout logic to take over
482491 stormService .Status .CanaryStatus = nil
483492
484- // Use single patch operation for the final status update
485- original := stormService .DeepCopy ()
486493 if err := r .Status ().Patch (ctx , stormService , client .MergeFrom (original )); err != nil {
487494 return ctrl.Result {}, fmt .Errorf ("failed to clear canary status and promote revision: %w" , err )
488495 }
0 commit comments