fix(coderd): wake dormant workspace when attempting to start it (#21306)

Relates to #20925

This PR modifies the `postWorkspaceBuild` handler to automatically unset
dormancy on a workspace when a start transition is requested.
Previously, the client was responsible for unsetting the dormancy on the
workspace prior to posting a workspace build.
This commit is contained in:
Cian Johnston
2025-12-18 10:35:04 +00:00
committed by GitHub
parent cac6d4ce98
commit 8248fa3b84
2 changed files with 69 additions and 10 deletions
+35 -10
View File
@@ -4244,10 +4244,16 @@ func TestWorkspaceDormant(t *testing.T) {
require.True(t, workspace.LastUsedAt.After(lastUsedAt))
})
t.Run("CannotStart", func(t *testing.T) {
// #20925: this test originally validated that you could **not** start a dormant workspace.
// The client was required to explicitly update the dormancy status before starting.
// This led to a 'whack-a-mole' situation where various code paths that create a workspace build
// would need to special case dormant workspaces.
// Now, a dormant workspace will automatically 'wake up' on start.
t.Run("StartWakesUpDormantWorkspace", func(t *testing.T) {
t.Parallel()
var (
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
auditor = audit.NewMock()
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Auditor: auditor})
user = coderdtest.CreateFirstUser(t, client)
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
@@ -4267,18 +4273,37 @@ func TestWorkspaceDormant(t *testing.T) {
// Should be able to stop a workspace while it is dormant.
coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop)
// Should not be able to start a workspace while it is dormant.
_, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
// Reset the auditor
auditor.ResetLogs()
// Assert test invariant: workspace is dormant.
workspace, err = client.Workspace(ctx, workspace.ID)
require.NoError(t, err, "fetch dormant workspace")
if assert.NotNil(t, workspace.DormantAt, "workspace must be dormant") {
require.WithinDuration(t, *workspace.DormantAt, time.Now(), 10*time.Second)
}
// Starting a dormant workspace should 'wake' it.
wb, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
TemplateVersionID: template.ActiveVersionID,
Transition: codersdk.WorkspaceTransition(database.WorkspaceTransitionStart),
})
require.Error(t, err)
err = client.UpdateWorkspaceDormancy(ctx, workspace.ID, codersdk.UpdateWorkspaceDormancy{
Dormant: false,
})
require.NoError(t, err)
coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStop, codersdk.WorkspaceTransitionStart)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, wb.ID)
// After starting, the workspace should no longer be dormant.
updatedWs, err := client.Workspace(ctx, workspace.ID)
require.NoError(t, err, "fetch updated workspace")
require.Nil(t, updatedWs.DormantAt)
// There should be an audit log for both the dormancy update and the start.
require.Len(t, auditor.AuditLogs(), 2)
require.True(t, auditor.Contains(t, database.AuditLog{
Action: database.AuditActionWrite,
ResourceType: database.ResourceTypeWorkspace,
}))
require.True(t, auditor.Contains(t, database.AuditLog{
Action: database.AuditActionStart,
ResourceType: database.ResourceTypeWorkspaceBuild,
}))
})
}