Skip to content

Commit e1e352d

Browse files
authored
feat: add template activity_bump property (#11734)
Allows template admins to configure the activity bump duration. Defaults to 1h.
1 parent fead57f commit e1e352d

34 files changed

+354
-90
lines changed

cli/templateedit.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
2323
description string
2424
icon string
2525
defaultTTL time.Duration
26+
activityBump time.Duration
2627
maxTTL time.Duration
2728
autostopRequirementDaysOfWeek []string
2829
autostopRequirementWeeks int64
@@ -108,6 +109,10 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
108109
defaultTTL = time.Duration(template.DefaultTTLMillis) * time.Millisecond
109110
}
110111

112+
if !userSetOption(inv, "activity-bump") {
113+
activityBump = time.Duration(template.ActivityBumpMillis) * time.Millisecond
114+
}
115+
111116
if !userSetOption(inv, "allow-user-autostop") {
112117
allowUserAutostop = template.AllowUserAutostop
113118
}
@@ -168,12 +173,13 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
168173
}
169174

170175
req := codersdk.UpdateTemplateMeta{
171-
Name: name,
172-
DisplayName: displayName,
173-
Description: description,
174-
Icon: icon,
175-
DefaultTTLMillis: defaultTTL.Milliseconds(),
176-
MaxTTLMillis: maxTTL.Milliseconds(),
176+
Name: name,
177+
DisplayName: displayName,
178+
Description: description,
179+
Icon: icon,
180+
DefaultTTLMillis: defaultTTL.Milliseconds(),
181+
ActivityBumpMillis: activityBump.Milliseconds(),
182+
MaxTTLMillis: maxTTL.Milliseconds(),
177183
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
178184
DaysOfWeek: autostopRequirementDaysOfWeek,
179185
Weeks: autostopRequirementWeeks,
@@ -233,6 +239,11 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
233239
Description: "Edit the template default time before shutdown - workspaces created from this template default to this value. Maps to \"Default autostop\" in the UI.",
234240
Value: clibase.DurationOf(&defaultTTL),
235241
},
242+
{
243+
Flag: "activity-bump",
244+
Description: "Edit the template activity bump - workspaces created from this template will have their shutdown time bumped by this value when activity is detected. Maps to \"Activity bump\" in the UI.",
245+
Value: clibase.DurationOf(&activityBump),
246+
},
236247
{
237248
Flag: "max-ttl",
238249
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting, regardless of user activity. This is an enterprise-only feature. Maps to \"Max lifetime\" in the UI.",

cli/templateedit_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ func TestTemplateEdit(t *testing.T) {
9393
"--description", template.Description,
9494
"--icon", template.Icon,
9595
"--default-ttl", (time.Duration(template.DefaultTTLMillis) * time.Millisecond).String(),
96+
"--activity-bump", (time.Duration(template.ActivityBumpMillis) * time.Millisecond).String(),
9697
"--allow-user-cancel-workspace-jobs=" + strconv.FormatBool(template.AllowUserCancelWorkspaceJobs),
9798
}
9899
inv, root := clitest.New(t, cmdArgs...)

cli/testdata/coder_templates_edit_--help.golden

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ USAGE:
66
Edit the metadata of a template by name.
77

88
OPTIONS:
9+
--activity-bump duration
10+
Edit the template activity bump - workspaces created from this
11+
template will have their shutdown time bumped by this value when
12+
activity is detected. Maps to "Activity bump" in the UI.
13+
914
--allow-user-autostart bool (default: true)
1015
Allow users to configure autostart for workspaces on this template.
1116
This can only be disabled in enterprise.

coderd/agentapi/activitybump_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
4141
maxDeadlineOffset *time.Duration
4242
workspaceTTL time.Duration
4343
templateTTL time.Duration
44+
templateActivityBump time.Duration
4445
templateDisallowsUserAutostop bool
4546
expectedBump time.Duration
4647
// If the tests get queued, we need to be able to set the next autostart
@@ -137,6 +138,26 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
137138
expectedBump: 10*time.Hour + (time.Minute * 30),
138139
nextAutostart: func(now time.Time) time.Time { return now.Add(time.Minute * 30) },
139140
},
141+
{
142+
// Custom activity bump duration specified on the template.
143+
name: "TemplateCustomActivityBump",
144+
transition: database.WorkspaceTransitionStart,
145+
jobCompletedAt: sql.NullTime{Valid: true, Time: dbtime.Now().Add(-30 * time.Minute)},
146+
buildDeadlineOffset: ptr.Ref(-30 * time.Minute),
147+
workspaceTTL: 8 * time.Hour,
148+
templateActivityBump: 5 * time.Hour, // instead of default 1h
149+
expectedBump: 5 * time.Hour,
150+
},
151+
{
152+
// Activity bump duration is 0.
153+
name: "TemplateCustomActivityBumpZero",
154+
transition: database.WorkspaceTransitionStart,
155+
jobCompletedAt: sql.NullTime{Valid: true, Time: dbtime.Now().Add(-30 * time.Minute)},
156+
buildDeadlineOffset: ptr.Ref(-30 * time.Minute),
157+
workspaceTTL: 8 * time.Hour,
158+
templateActivityBump: -1, // negative values get changed to 0 in the test
159+
expectedBump: 0,
160+
},
140161
} {
141162
tt := tt
142163
for _, tz := range timezones {
@@ -186,11 +207,19 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
186207
buildID = uuid.New()
187208
)
188209

210+
activityBump := 1 * time.Hour
211+
if tt.templateActivityBump < 0 {
212+
// less than 0 => 0
213+
activityBump = 0
214+
} else if tt.templateActivityBump != 0 {
215+
activityBump = tt.templateActivityBump
216+
}
189217
require.NoError(t, db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
190218
ID: template.ID,
191219
UpdatedAt: dbtime.Now(),
192220
AllowUserAutostop: !tt.templateDisallowsUserAutostop,
193221
DefaultTTL: int64(tt.templateTTL),
222+
ActivityBump: int64(activityBump),
194223
}), "unexpected error updating template schedule")
195224

196225
var buildNumber int32 = 1

coderd/apidoc/docs.go

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmem/dbmem.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -841,10 +841,14 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
841841
if err != nil {
842842
return err
843843
}
844+
if template.ActivityBump == 0 {
845+
return nil
846+
}
847+
activityBump := time.Duration(template.ActivityBump)
844848

845849
var ttlDur time.Duration
846-
if now.Add(time.Hour).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
847-
// Extend to TTL
850+
if now.Add(activityBump).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
851+
// Extend to TTL (NOT activity bump)
848852
add := arg.NextAutostart.Sub(now)
849853
if workspace.Ttl.Valid && template.AllowUserAutostop {
850854
add += time.Duration(workspace.Ttl.Int64)
@@ -853,7 +857,8 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
853857
}
854858
ttlDur = add
855859
} else {
856-
ttlDur = time.Hour
860+
// Otherwise, default to regular activity bump duration.
861+
ttlDur = activityBump
857862
}
858863

859864
// Only bump if 5% of the deadline has passed.
@@ -6543,6 +6548,7 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database
65436548
tpl.AllowUserAutostop = arg.AllowUserAutostop
65446549
tpl.UpdatedAt = dbtime.Now()
65456550
tpl.DefaultTTL = arg.DefaultTTL
6551+
tpl.ActivityBump = arg.ActivityBump
65466552
tpl.UseMaxTtl = arg.UseMaxTtl
65476553
tpl.MaxTTL = arg.MaxTTL
65486554
tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek

coderd/database/dump.sql

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
DROP VIEW template_with_users;
2+
3+
ALTER TABLE templates DROP COLUMN activity_bump;
4+
5+
CREATE VIEW
6+
template_with_users
7+
AS
8+
SELECT
9+
templates.*,
10+
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
11+
coalesce(visible_users.username, '') AS created_by_username
12+
FROM
13+
templates
14+
LEFT JOIN
15+
visible_users
16+
ON
17+
templates.created_by = visible_users.id;
18+
19+
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
ALTER TABLE templates ADD COLUMN activity_bump bigint DEFAULT '3600000000000'::bigint NOT NULL; -- 1 hour
2+
3+
DROP VIEW template_with_users;
4+
5+
CREATE VIEW
6+
template_with_users
7+
AS
8+
SELECT
9+
templates.*,
10+
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
11+
coalesce(visible_users.username, '') AS created_by_username
12+
FROM
13+
templates
14+
LEFT JOIN
15+
visible_users
16+
ON
17+
templates.created_by = visible_users.id;
18+
19+
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';

coderd/database/modelqueries.go

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
9090
&i.RequireActiveVersion,
9191
&i.Deprecated,
9292
&i.UseMaxTtl,
93+
&i.ActivityBump,
9394
&i.CreatedByAvatarURL,
9495
&i.CreatedByUsername,
9596
); err != nil {

coderd/database/models.go

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/querier.go

+7-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)