Skip to content

Commit 2334ea9

Browse files
authored
fix: fail, not succeed, workflows terminated while pending on a sync lock (cherry-pick #16776 for 4.0) (#16791)
Signed-off-by: Alan Clucas <alan@clucas.org>
1 parent cbf8cfa commit 2334ea9

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

‎workflow/controller/operator.go‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,11 @@ func (woc *wfOperationCtx) operate(ctx context.Context) {
292292
phase = wfv1.WorkflowPending
293293
}
294294
woc.markWorkflowPhase(ctx, phase, msg)
295-
return
296295
}
296+
// Whether the workflow remains queued or its locks were just
297+
// released for shutdown, there is nothing more to do this
298+
// reconcile.
299+
return
297300
}
298301
}
299302

@@ -564,7 +567,10 @@ func (woc *wfOperationCtx) releaseLocksForPendingShuttingdownWfs(ctx context.Con
564567
if woc.GetShutdownStrategy().Enabled() && woc.wf.Status.Phase == wfv1.WorkflowPending && woc.GetShutdownStrategy() == wfv1.ShutdownStrategyTerminate {
565568
if woc.controller.syncManager.ReleaseAll(ctx, woc.execWf) {
566569
woc.log.WithFields(logging.Fields{"key": woc.execWf.Name}).Info(ctx, "Released all locks since this pending workflow is being shutdown")
567-
woc.markWorkflowSuccess(ctx)
570+
// The workflow never started: it was still waiting for its
571+
// synchronization lock when it was terminated, so it completes as
572+
// Failed, matching every other shutdown path.
573+
woc.markWorkflowFailed(ctx, fmt.Sprintf("Stopped with strategy '%s'", woc.GetShutdownStrategy()))
568574
return true
569575
}
570576
}

‎workflow/controller/operator_concurrency_test.go‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -987,11 +987,32 @@ func TestSynchronizationForPendingShuttingdownWfs(t *testing.T) {
987987
wfTwo, err = controller.wfclientset.ArgoprojV1alpha1().Workflows(wf.Namespace).Patch(ctx, wfTwo.Name, types.MergePatchType, patch, metav1.PatchOptions{})
988988
require.NoError(t, err)
989989

990-
// The pending workflow that's being shutdown should have succeeded and released the lock.
990+
// The pending workflow that's being shutdown should have failed and released the lock.
991991
wocTwo = newWorkflowOperationCtx(ctx, wfTwo, controller)
992992
wocTwo.operate(ctx)
993-
assert.Equal(t, wfv1.WorkflowSucceeded, wocTwo.execWf.Status.Phase)
993+
assert.Equal(t, wfv1.WorkflowFailed, wocTwo.wf.Status.Phase)
994+
assert.Equal(t, "Stopped with strategy 'Terminate'", wocTwo.wf.Status.Message)
994995
assert.Nil(t, wocTwo.wf.Status.Synchronization)
996+
// The workflow never ran, so no nodes should have been created for it.
997+
assert.Empty(t, wocTwo.wf.Status.Nodes)
998+
999+
// Release the lock from the first workflow.
1000+
woc.wf.Status.Phase = wfv1.WorkflowSucceeded
1001+
woc.operate(ctx)
1002+
assert.Nil(t, woc.wf.Status.Synchronization)
1003+
1004+
// The terminated workflow must also have been removed from the lock's
1005+
// waiting queue, so a new workflow acquires the lock immediately.
1006+
wfThree := wf.DeepCopy()
1007+
wfThree.Name = "three-terminating"
1008+
wfThree, err = controller.wfclientset.ArgoprojV1alpha1().Workflows(wf.Namespace).Create(ctx, wfThree, metav1.CreateOptions{})
1009+
require.NoError(t, err)
1010+
wocThree := newWorkflowOperationCtx(ctx, wfThree, controller)
1011+
wocThree.operate(ctx)
1012+
assert.Equal(t, wfv1.WorkflowRunning, wocThree.wf.Status.Phase)
1013+
require.NotNil(t, wocThree.wf.Status.Synchronization)
1014+
require.NotNil(t, wocThree.wf.Status.Synchronization.Mutex)
1015+
assert.Len(t, wocThree.wf.Status.Synchronization.Mutex.Holding, 1)
9951016
})
9961017

9971018
t.Run("PendingShuttingdownStoppingWf", func(t *testing.T) {

0 commit comments

Comments
 (0)