Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit560cf84

Browse files
authored
fix: prevent activity bump for prebuilt workspaces (#19263)
## DescriptionThis PR ensures that activity-based deadline extensions ("activitybumping") are not applied to prebuilt workspaces. Prebuilds are managedby the reconciliation loop and must not have `deadline` or`max_deadline` values set or extended, as they are not part of theregular lifecycle executor path.## Changes- Update `ActivityBumpWorkspace` SQL query to discard prebuiltworkspaces- Update application layer to avoid calling activity bump logic onprebuilt workspacesRelated with: * Issue:#18898* PR:#19252
1 parentcd1faff commit560cf84

File tree

4 files changed

+148
-28
lines changed

4 files changed

+148
-28
lines changed

‎coderd/database/queries.sql.go‎

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/activitybump.sql‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ WITH latest AS (
2222
-- be as if the workspace auto started at the given time and the
2323
-- original TTL was applied.
2424
--
25-
-- Sadly we can't define`activity_bump_interval` above since
25+
-- Sadly we can't define'activity_bump_interval' above since
2626
-- it won't be available for this CASE statement, so we have to
2727
-- copy the cast twice.
2828
WHEN NOW()+ (templates.activity_bump/1000/1000/1000||' seconds')::interval> @next_autostart ::timestamptz
@@ -52,7 +52,11 @@ WITH latest AS (
5252
ONworkspaces.id=workspace_builds.workspace_id
5353
JOIN templates
5454
ONtemplates.id=workspaces.template_id
55-
WHEREworkspace_builds.workspace_id= @workspace_id::uuid
55+
WHERE
56+
workspace_builds.workspace_id= @workspace_id::uuid
57+
-- Prebuilt workspaces (identified by having the prebuilds system user as owner_id)
58+
-- are managed by the reconciliation loop and not subject to activity bumping
59+
ANDworkspaces.owner_id!='c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID
5660
ORDER BYworkspace_builds.build_numberDESC
5761
LIMIT1
5862
)

‎coderd/workspacestats/reporter.go‎

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -149,33 +149,36 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac
149149
returnnil
150150
}
151151

152-
// check next autostart
153-
varnextAutostart time.Time
154-
ifworkspace.AutostartSchedule.String!="" {
155-
templateSchedule,err:= (*(r.opts.TemplateScheduleStore.Load())).Get(ctx,r.opts.Database,workspace.TemplateID)
156-
// If the template schedule fails to load, just default to bumping
157-
// without the next transition and log it.
158-
switch {
159-
caseerr==nil:
160-
next,allowed:=schedule.NextAutostart(now,workspace.AutostartSchedule.String,templateSchedule)
161-
ifallowed {
162-
nextAutostart=next
152+
// Prebuilds are not subject to activity-based deadline bumps
153+
if!workspace.IsPrebuild() {
154+
// check next autostart
155+
varnextAutostart time.Time
156+
ifworkspace.AutostartSchedule.String!="" {
157+
templateSchedule,err:= (*(r.opts.TemplateScheduleStore.Load())).Get(ctx,r.opts.Database,workspace.TemplateID)
158+
// If the template schedule fails to load, just default to bumping
159+
// without the next transition and log it.
160+
switch {
161+
caseerr==nil:
162+
next,allowed:=schedule.NextAutostart(now,workspace.AutostartSchedule.String,templateSchedule)
163+
ifallowed {
164+
nextAutostart=next
165+
}
166+
casedatabase.IsQueryCanceledError(err):
167+
r.opts.Logger.Debug(ctx,"query canceled while loading template schedule",
168+
slog.F("workspace_id",workspace.ID),
169+
slog.F("template_id",workspace.TemplateID))
170+
default:
171+
r.opts.Logger.Error(ctx,"failed to load template schedule bumping activity, defaulting to bumping by 60min",
172+
slog.F("workspace_id",workspace.ID),
173+
slog.F("template_id",workspace.TemplateID),
174+
slog.Error(err),
175+
)
163176
}
164-
casedatabase.IsQueryCanceledError(err):
165-
r.opts.Logger.Debug(ctx,"query canceled while loading template schedule",
166-
slog.F("workspace_id",workspace.ID),
167-
slog.F("template_id",workspace.TemplateID))
168-
default:
169-
r.opts.Logger.Error(ctx,"failed to load template schedule bumping activity, defaulting to bumping by 60min",
170-
slog.F("workspace_id",workspace.ID),
171-
slog.F("template_id",workspace.TemplateID),
172-
slog.Error(err),
173-
)
174177
}
175-
}
176178

177-
// bump workspace activity
178-
ActivityBumpWorkspace(ctx,r.opts.Logger.Named("activity_bump"),r.opts.Database,workspace.ID,nextAutostart)
179+
// bump workspace activity
180+
ActivityBumpWorkspace(ctx,r.opts.Logger.Named("activity_bump"),r.opts.Database,workspace.ID,nextAutostart)
181+
}
179182

180183
// bump workspace last_used_at
181184
r.opts.UsageTracker.Add(workspace.ID)

‎enterprise/coderd/workspaces_test.go‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
agplschedule"github.com/coder/coder/v2/coderd/schedule"
4343
"github.com/coder/coder/v2/coderd/schedule/cron"
4444
"github.com/coder/coder/v2/coderd/util/ptr"
45+
"github.com/coder/coder/v2/coderd/workspacestats"
4546
"github.com/coder/coder/v2/codersdk"
4647
entaudit"github.com/coder/coder/v2/enterprise/audit"
4748
"github.com/coder/coder/v2/enterprise/audit/backends"
@@ -2767,6 +2768,114 @@ func TestPrebuildUpdateLifecycleParams(t *testing.T) {
27672768
}
27682769
}
27692770

2771+
funcTestPrebuildActivityBump(t*testing.T) {
2772+
t.Parallel()
2773+
2774+
clock:=quartz.NewMock(t)
2775+
clock.Set(dbtime.Now())
2776+
2777+
// Setup
2778+
log:=testutil.Logger(t)
2779+
client,db,owner:=coderdenttest.NewWithDatabase(t,&coderdenttest.Options{
2780+
Options:&coderdtest.Options{
2781+
IncludeProvisionerDaemon:true,
2782+
Clock:clock,
2783+
},
2784+
LicenseOptions:&coderdenttest.LicenseOptions{
2785+
Features: license.Features{
2786+
codersdk.FeatureWorkspacePrebuilds:1,
2787+
},
2788+
},
2789+
})
2790+
2791+
// Given: a template and a template version with preset and a prebuilt workspace
2792+
presetID:=uuid.New()
2793+
version:=coderdtest.CreateTemplateVersion(t,client,owner.OrganizationID,nil)
2794+
_=coderdtest.AwaitTemplateVersionJobCompleted(t,client,version.ID)
2795+
// Configure activity bump on the template
2796+
activityBump:=time.Hour
2797+
template:=coderdtest.CreateTemplate(t,client,owner.OrganizationID,version.ID,func(ctr*codersdk.CreateTemplateRequest) {
2798+
ctr.ActivityBumpMillis= ptr.Ref[int64](activityBump.Milliseconds())
2799+
})
2800+
dbgen.Preset(t,db, database.InsertPresetParams{
2801+
ID:presetID,
2802+
TemplateVersionID:version.ID,
2803+
DesiredInstances: sql.NullInt32{Int32:1,Valid:true},
2804+
})
2805+
// Given: a prebuild with an expired Deadline
2806+
deadline:=clock.Now().Add(-30*time.Minute)
2807+
wb:=dbfake.WorkspaceBuild(t,db, database.WorkspaceTable{
2808+
OwnerID:database.PrebuildsSystemUserID,
2809+
TemplateID:template.ID,
2810+
}).Seed(database.WorkspaceBuild{
2811+
TemplateVersionID:version.ID,
2812+
TemplateVersionPresetID: uuid.NullUUID{
2813+
UUID:presetID,
2814+
Valid:true,
2815+
},
2816+
Deadline:deadline,
2817+
}).WithAgent(func(agent []*proto.Agent) []*proto.Agent {
2818+
returnagent
2819+
}).Do()
2820+
2821+
// Mark the prebuilt workspace's agent as ready so the prebuild can be claimed
2822+
// nolint:gocritic
2823+
ctx:=dbauthz.AsSystemRestricted(testutil.Context(t,testutil.WaitLong))
2824+
agent,err:=db.GetWorkspaceAgentAndLatestBuildByAuthToken(ctx,uuid.MustParse(wb.AgentToken))
2825+
require.NoError(t,err)
2826+
err=db.UpdateWorkspaceAgentLifecycleStateByID(ctx, database.UpdateWorkspaceAgentLifecycleStateByIDParams{
2827+
ID:agent.WorkspaceAgent.ID,
2828+
LifecycleState:database.WorkspaceAgentLifecycleStateReady,
2829+
})
2830+
require.NoError(t,err)
2831+
2832+
// Given: a prebuilt workspace with a Deadline and an empty MaxDeadline
2833+
prebuild:=coderdtest.MustWorkspace(t,client,wb.Workspace.ID)
2834+
require.Equal(t,deadline.UTC(),prebuild.LatestBuild.Deadline.Time.UTC())
2835+
require.Zero(t,prebuild.LatestBuild.MaxDeadline)
2836+
2837+
// When: activity bump is applied to an unclaimed prebuild
2838+
workspacestats.ActivityBumpWorkspace(ctx,log,db,prebuild.ID,clock.Now().Add(10*time.Hour))
2839+
2840+
// Then: prebuild Deadline/MaxDeadline remain unchanged
2841+
prebuild=coderdtest.MustWorkspace(t,client,wb.Workspace.ID)
2842+
require.Equal(t,deadline.UTC(),prebuild.LatestBuild.Deadline.Time.UTC())
2843+
require.Zero(t,prebuild.LatestBuild.MaxDeadline)
2844+
2845+
// Given: the prebuilt workspace is claimed by a user
2846+
user,err:=client.User(ctx,"testUser")
2847+
require.NoError(t,err)
2848+
claimedWorkspace,err:=client.CreateUserWorkspace(ctx,user.ID.String(), codersdk.CreateWorkspaceRequest{
2849+
TemplateVersionID:version.ID,
2850+
TemplateVersionPresetID:presetID,
2851+
Name:coderdtest.RandomUsername(t),
2852+
})
2853+
require.NoError(t,err)
2854+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,claimedWorkspace.LatestBuild.ID)
2855+
workspace:=coderdtest.MustWorkspace(t,client,claimedWorkspace.ID)
2856+
require.Equal(t,prebuild.ID,workspace.ID)
2857+
// Claimed workspaces have an empty Deadline and MaxDeadline
2858+
require.Zero(t,workspace.LatestBuild.Deadline)
2859+
require.Zero(t,workspace.LatestBuild.MaxDeadline)
2860+
2861+
// Given: the claimed workspace has an expired Deadline
2862+
err=db.UpdateWorkspaceBuildDeadlineByID(ctx, database.UpdateWorkspaceBuildDeadlineByIDParams{
2863+
ID:workspace.LatestBuild.ID,
2864+
Deadline:deadline,
2865+
UpdatedAt:clock.Now(),
2866+
})
2867+
require.NoError(t,err)
2868+
workspace=coderdtest.MustWorkspace(t,client,claimedWorkspace.ID)
2869+
2870+
// When: activity bump is applied to a claimed prebuild
2871+
workspacestats.ActivityBumpWorkspace(ctx,log,db,workspace.ID,clock.Now().Add(10*time.Hour))
2872+
2873+
// Then: Deadline is extended by the activity bump, MaxDeadline remains unset
2874+
workspace=coderdtest.MustWorkspace(t,client,claimedWorkspace.ID)
2875+
require.WithinDuration(t,clock.Now().Add(activityBump).UTC(),workspace.LatestBuild.Deadline.Time.UTC(),testutil.WaitMedium)
2876+
require.Zero(t,workspace.LatestBuild.MaxDeadline)
2877+
}
2878+
27702879
// TestWorkspaceTemplateParamsChange tests a workspace with a parameter that
27712880
// validation changes on apply. The params used in create workspace are invalid
27722881
// according to the static params on import.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp