mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix(coderd): use BuildReasonTaskAutoPause for task workspaces (#22126)
Relates to https://github.com/coder/internal/issues/1252 When a workspace with a TaskID hits its deadline, use BuildReasonTaskAutoPause instead of BuildReasonAutostop. This allows downstream systems to distinguish between regular autostop and task workspace pauses. Created by Mux using Opus 4.5.
This commit is contained in:
@@ -525,10 +525,18 @@ func getNextTransition(
|
||||
) {
|
||||
switch {
|
||||
case isEligibleForAutostop(user, ws, latestBuild, latestJob, currentTick):
|
||||
// Use task-specific reason for AI task workspaces.
|
||||
if ws.TaskID.Valid {
|
||||
return database.WorkspaceTransitionStop, database.BuildReasonTaskAutoPause, nil
|
||||
}
|
||||
return database.WorkspaceTransitionStop, database.BuildReasonAutostop, nil
|
||||
case isEligibleForAutostart(user, ws, latestBuild, latestJob, templateSchedule, currentTick):
|
||||
return database.WorkspaceTransitionStart, database.BuildReasonAutostart, nil
|
||||
case isEligibleForFailedStop(latestBuild, latestJob, templateSchedule, currentTick):
|
||||
// Use task-specific reason for AI task workspaces.
|
||||
if ws.TaskID.Valid {
|
||||
return database.WorkspaceTransitionStop, database.BuildReasonTaskAutoPause, nil
|
||||
}
|
||||
return database.WorkspaceTransitionStop, database.BuildReasonAutostop, nil
|
||||
case isEligibleForDormantStop(ws, templateSchedule, currentTick):
|
||||
// Only stop started workspaces.
|
||||
|
||||
@@ -5,12 +5,113 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/schedule"
|
||||
)
|
||||
|
||||
func Test_getNextTransition_TaskAutoPause(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Set up a workspace that is eligible for autostop (past deadline).
|
||||
now := time.Now()
|
||||
pastDeadline := now.Add(-time.Hour)
|
||||
|
||||
okUser := database.User{Status: database.UserStatusActive}
|
||||
okBuild := database.WorkspaceBuild{
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
Deadline: pastDeadline,
|
||||
}
|
||||
okJob := database.ProvisionerJob{
|
||||
JobStatus: database.ProvisionerJobStatusSucceeded,
|
||||
}
|
||||
okTemplateSchedule := schedule.TemplateScheduleOptions{}
|
||||
|
||||
// Failed build setup for failedstop tests.
|
||||
failedBuild := database.WorkspaceBuild{
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
}
|
||||
failedJob := database.ProvisionerJob{
|
||||
JobStatus: database.ProvisionerJobStatusFailed,
|
||||
CompletedAt: sql.NullTime{Time: now.Add(-time.Hour), Valid: true},
|
||||
}
|
||||
failedTemplateSchedule := schedule.TemplateScheduleOptions{
|
||||
FailureTTL: time.Minute, // TTL already elapsed since job completed an hour ago.
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Workspace database.Workspace
|
||||
Build database.WorkspaceBuild
|
||||
Job database.ProvisionerJob
|
||||
TemplateSchedule schedule.TemplateScheduleOptions
|
||||
ExpectedReason database.BuildReason
|
||||
}{
|
||||
{
|
||||
Name: "RegularWorkspace_Autostop",
|
||||
Workspace: database.Workspace{
|
||||
DormantAt: sql.NullTime{Valid: false},
|
||||
},
|
||||
Build: okBuild,
|
||||
Job: okJob,
|
||||
TemplateSchedule: okTemplateSchedule,
|
||||
ExpectedReason: database.BuildReasonAutostop,
|
||||
},
|
||||
{
|
||||
Name: "TaskWorkspace_Autostop_UsesTaskAutoPause",
|
||||
Workspace: database.Workspace{
|
||||
DormantAt: sql.NullTime{Valid: false},
|
||||
TaskID: uuid.NullUUID{UUID: uuid.New(), Valid: true},
|
||||
},
|
||||
Build: okBuild,
|
||||
Job: okJob,
|
||||
TemplateSchedule: okTemplateSchedule,
|
||||
ExpectedReason: database.BuildReasonTaskAutoPause,
|
||||
},
|
||||
{
|
||||
Name: "RegularWorkspace_FailedStop",
|
||||
Workspace: database.Workspace{
|
||||
DormantAt: sql.NullTime{Valid: false},
|
||||
},
|
||||
Build: failedBuild,
|
||||
Job: failedJob,
|
||||
TemplateSchedule: failedTemplateSchedule,
|
||||
ExpectedReason: database.BuildReasonAutostop,
|
||||
},
|
||||
{
|
||||
Name: "TaskWorkspace_FailedStop_UsesTaskAutoPause",
|
||||
Workspace: database.Workspace{
|
||||
DormantAt: sql.NullTime{Valid: false},
|
||||
TaskID: uuid.NullUUID{UUID: uuid.New(), Valid: true},
|
||||
},
|
||||
Build: failedBuild,
|
||||
Job: failedJob,
|
||||
TemplateSchedule: failedTemplateSchedule,
|
||||
ExpectedReason: database.BuildReasonTaskAutoPause,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
transition, reason, err := getNextTransition(
|
||||
okUser,
|
||||
tc.Workspace,
|
||||
tc.Build,
|
||||
tc.Job,
|
||||
tc.TemplateSchedule,
|
||||
now,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, database.WorkspaceTransitionStop, transition)
|
||||
require.Equal(t, tc.ExpectedReason, reason)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isEligibleForAutostart(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -2019,5 +2019,11 @@ func TestExecutorTaskWorkspace(t *testing.T) {
|
||||
assert.Contains(t, stats.Transitions, workspace.ID, "task workspace should be in transitions")
|
||||
assert.Equal(t, database.WorkspaceTransitionStop, stats.Transitions[workspace.ID], "should autostop the workspace")
|
||||
require.Empty(t, stats.Errors, "should have no errors when managing task workspaces")
|
||||
|
||||
// Then: The build reason should be TaskAutoPause (not regular Autostop)
|
||||
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
|
||||
_ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
|
||||
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
|
||||
assert.Equal(t, codersdk.BuildReasonTaskAutoPause, workspace.LatestBuild.Reason, "task workspace should use TaskAutoPause build reason")
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user