diff --git a/client/restarts.go b/client/restarts.go index 5fd3216ce..ebdc62cff 100644 --- a/client/restarts.go +++ b/client/restarts.go @@ -127,10 +127,15 @@ func (r *RestartTracker) GetState() (string, time.Duration) { // Hot path if no attempts are expected if r.policy.Attempts == 0 { r.reason = ReasonNoRestartsAllowed - if r.waitRes != nil && r.waitRes.Successful() { + + // If the task does not restart on a successful exit code and + // the exit code was successful: terminate. + if !r.onSuccess && r.waitRes != nil && r.waitRes.Successful() { return structs.TaskTerminated, 0 } + // Task restarts even on a successful exit code but no restarts + // allowed. return structs.TaskNotRestarting, 0 } diff --git a/client/restarts_test.go b/client/restarts_test.go index b0cad5b1a..915902e04 100644 --- a/client/restarts_test.go +++ b/client/restarts_test.go @@ -88,9 +88,32 @@ func TestClient_RestartTracker_ZeroAttempts(t *testing.T) { t.Parallel() p := testPolicy(true, structs.RestartPolicyModeFail) p.Attempts = 0 + + // Test with a non-zero exit code rt := newRestartTracker(p, structs.JobTypeService) if state, when := rt.SetWaitResult(testWaitResult(1)).GetState(); state != structs.TaskNotRestarting { - t.Fatalf("expect no restart, got restart/delay: %v", when) + t.Fatalf("expect no restart, got restart/delay: %v/%v", state, when) + } + + // Even with a zero (successful) exit code non-batch jobs should exit + // with TaskNotRestarting + rt = newRestartTracker(p, structs.JobTypeService) + if state, when := rt.SetWaitResult(testWaitResult(0)).GetState(); state != structs.TaskNotRestarting { + t.Fatalf("expect no restart, got restart/delay: %v/%v", state, when) + } + + // Batch jobs with a zero exit code and 0 attempts *do* exit cleanly + // with Terminated + rt = newRestartTracker(p, structs.JobTypeBatch) + if state, when := rt.SetWaitResult(testWaitResult(0)).GetState(); state != structs.TaskTerminated { + t.Fatalf("expect terminated, got restart/delay: %v/%v", state, when) + } + + // Batch jobs with a non-zero exit code and 0 attempts exit with + // TaskNotRestarting + rt = newRestartTracker(p, structs.JobTypeBatch) + if state, when := rt.SetWaitResult(testWaitResult(1)).GetState(); state != structs.TaskNotRestarting { + t.Fatalf("expect no restart, got restart/delay: %v/%v", state, when) } }