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

Commit0f6ca55

Browse files
feat: implement scheduling mechanism for prebuilds (#18126)
Closescoder/internal#312Depends oncoder/terraform-provider-coder#408This PR adds support for defining an **autoscaling block** forprebuilds, allowing number of desired instances to scale dynamicallybased on a schedule.Example usage:```data "coder_workspace_preset" "us-nix" { ... prebuilds = { instances = 0 # default to 0 instances scheduling = { timezone = "UTC" # a single timezone is used for simplicity # Scale to 3 instances during the work week schedule { cron = "* 8-18 * * 1-5" # from 8AM–6:59PM, Mon–Fri, UTC instances = 3 # scale to 3 instances } # Scale to 1 instance on Saturdays for urgent support queries schedule { cron = "* 8-14 * * 6" # from 8AM–2:59PM, Sat, UTC instances = 1 # scale to 1 instance } } }}```### Behavior- Multiple `schedule` blocks per `prebuilds` block are supported.- If the current time matches any defined autoscaling schedule, thecorresponding number of instances is used.- If no schedule matches, the **default instance count**(`prebuilds.instances`) is used as a fallback.### WhyThis feature allows prebuild instance capacity to adapt to predictableusage patterns, such as:- Scaling up during business hours or high-demand periods- Reducing capacity during off-hours to save resources### Cron specificationThe cron specification is interpreted as a **continuous time range.**For example, the expression:```* 9-18 * * 1-5```is intended to represent a continuous range from **09:00 to 18:59**,Monday through Friday.However, due to minor implementation imprecision, it is currentlyinterpreted as a range from **08:59:00 to 18:58:59**, Monday throughFriday.This slight discrepancy arises because the evaluation is based onwhether a specific **point in time** falls within the range, using the`github.com/coder/coder/v2/coderd/schedule/cron` library, which performsper-minute matching rather than strict range evaluation.---------Co-authored-by: Danny Kopping <danny@coder.com>
1 parent511fd09 commit0f6ca55

File tree

38 files changed

+2528
-871
lines changed

38 files changed

+2528
-871
lines changed

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,13 @@ func (q *querier) GetAPIKeysLastUsedAfter(ctx context.Context, lastUsed time.Tim
16861686
returnfetchWithPostFilter(q.auth,policy.ActionRead,q.db.GetAPIKeysLastUsedAfter)(ctx,lastUsed)
16871687
}
16881688

1689+
func (q*querier)GetActivePresetPrebuildSchedules(ctx context.Context) ([]database.TemplateVersionPresetPrebuildSchedule,error) {
1690+
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceTemplate.All());err!=nil {
1691+
returnnil,err
1692+
}
1693+
returnq.db.GetActivePresetPrebuildSchedules(ctx)
1694+
}
1695+
16891696
func (q*querier)GetActiveUserCount(ctx context.Context,includeSystembool) (int64,error) {
16901697
iferr:=q.authorizeContext(ctx,policy.ActionRead,rbac.ResourceSystem);err!=nil {
16911698
return0,err
@@ -3661,6 +3668,15 @@ func (q *querier) InsertPresetParameters(ctx context.Context, arg database.Inser
36613668
returnq.db.InsertPresetParameters(ctx,arg)
36623669
}
36633670

3671+
func (q*querier)InsertPresetPrebuildSchedule(ctx context.Context,arg database.InsertPresetPrebuildScheduleParams) (database.TemplateVersionPresetPrebuildSchedule,error) {
3672+
err:=q.authorizeContext(ctx,policy.ActionUpdate,rbac.ResourceTemplate)
3673+
iferr!=nil {
3674+
return database.TemplateVersionPresetPrebuildSchedule{},err
3675+
}
3676+
3677+
returnq.db.InsertPresetPrebuildSchedule(ctx,arg)
3678+
}
3679+
36643680
func (q*querier)InsertProvisionerJob(ctx context.Context,arg database.InsertProvisionerJobParams) (database.ProvisionerJob,error) {
36653681
// TODO: Remove this once we have a proper rbac check for provisioner jobs.
36663682
// Details in https://github.com/coder/coder/issues/16160

‎coderd/database/dbauthz/dbauthz_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,29 @@ func (s *MethodTestSuite) TestOrganization() {
979979
}
980980
check.Args(insertPresetParametersParams).Asserts(rbac.ResourceTemplate,policy.ActionUpdate)
981981
}))
982+
s.Run("InsertPresetPrebuildSchedule",s.Subtest(func(db database.Store,check*expects) {
983+
org:=dbgen.Organization(s.T(),db, database.Organization{})
984+
user:=dbgen.User(s.T(),db, database.User{})
985+
template:=dbgen.Template(s.T(),db, database.Template{
986+
CreatedBy:user.ID,
987+
OrganizationID:org.ID,
988+
})
989+
templateVersion:=dbgen.TemplateVersion(s.T(),db, database.TemplateVersion{
990+
TemplateID: uuid.NullUUID{UUID:template.ID,Valid:true},
991+
OrganizationID:org.ID,
992+
CreatedBy:user.ID,
993+
})
994+
preset:=dbgen.Preset(s.T(),db, database.InsertPresetParams{
995+
TemplateVersionID:templateVersion.ID,
996+
Name:"test",
997+
})
998+
arg:= database.InsertPresetPrebuildScheduleParams{
999+
PresetID:preset.ID,
1000+
}
1001+
check.Args(arg).
1002+
Asserts(rbac.ResourceTemplate,policy.ActionUpdate).
1003+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
1004+
}))
9821005
s.Run("DeleteOrganizationMember",s.Subtest(func(db database.Store,check*expects) {
9831006
o:=dbgen.Organization(s.T(),db, database.Organization{})
9841007
u:=dbgen.User(s.T(),db, database.User{})
@@ -4916,6 +4939,12 @@ func (s *MethodTestSuite) TestPrebuilds() {
49164939
Asserts(template.RBACObject(),policy.ActionRead).
49174940
Returns(insertedParameters)
49184941
}))
4942+
s.Run("GetActivePresetPrebuildSchedules",s.Subtest(func(db database.Store,check*expects) {
4943+
check.Args().
4944+
Asserts(rbac.ResourceTemplate.All(),policy.ActionRead).
4945+
Returns([]database.TemplateVersionPresetPrebuildSchedule{}).
4946+
ErrorsWithInMemDB(dbmem.ErrUnimplemented)
4947+
}))
49194948
s.Run("GetPresetsByTemplateVersionID",s.Subtest(func(db database.Store,check*expects) {
49204949
ctx:=context.Background()
49214950
org:=dbgen.Organization(s.T(),db, database.Organization{})

‎coderd/database/dbfake/dbfake.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ func (t TemplateVersionBuilder) Do() TemplateVersionResponse {
415415
CreatedAt:version.CreatedAt,
416416
DesiredInstances:preset.DesiredInstances,
417417
InvalidateAfterSecs:preset.InvalidateAfterSecs,
418+
SchedulingTimezone:preset.SchedulingTimezone,
418419
})
419420
}
420421

‎coderd/database/dbgen/dbgen.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,11 +1302,22 @@ func Preset(t testing.TB, db database.Store, seed database.InsertPresetParams) d
13021302
CreatedAt:takeFirst(seed.CreatedAt,dbtime.Now()),
13031303
DesiredInstances:seed.DesiredInstances,
13041304
InvalidateAfterSecs:seed.InvalidateAfterSecs,
1305+
SchedulingTimezone:seed.SchedulingTimezone,
13051306
})
13061307
require.NoError(t,err,"insert preset")
13071308
returnpreset
13081309
}
13091310

1311+
funcPresetPrebuildSchedule(t testing.TB,db database.Store,seed database.InsertPresetPrebuildScheduleParams) database.TemplateVersionPresetPrebuildSchedule {
1312+
schedule,err:=db.InsertPresetPrebuildSchedule(genCtx, database.InsertPresetPrebuildScheduleParams{
1313+
PresetID:takeFirst(seed.PresetID,uuid.New()),
1314+
CronExpression:takeFirst(seed.CronExpression,"* 9-18 * * 1-5"),
1315+
DesiredInstances:takeFirst(seed.DesiredInstances,1),
1316+
})
1317+
require.NoError(t,err,"insert preset prebuild schedule")
1318+
returnschedule
1319+
}
1320+
13101321
funcPresetParameter(t testing.TB,db database.Store,seed database.InsertPresetParametersParams) []database.TemplateVersionPresetParameter {
13111322
parameters,err:=db.InsertPresetParameters(genCtx, database.InsertPresetParametersParams{
13121323
TemplateVersionPresetID:takeFirst(seed.TemplateVersionPresetID,uuid.New()),

‎coderd/database/dbmem/dbmem.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,6 +2778,10 @@ func (q *FakeQuerier) GetAPIKeysLastUsedAfter(_ context.Context, after time.Time
27782778
returnapiKeys,nil
27792779
}
27802780

2781+
func (q*FakeQuerier)GetActivePresetPrebuildSchedules(ctx context.Context) ([]database.TemplateVersionPresetPrebuildSchedule,error) {
2782+
returnnil,ErrUnimplemented
2783+
}
2784+
27812785
// nolint:revive // It's not a control flag, it's a filter.
27822786
func (q*FakeQuerier)GetActiveUserCount(_ context.Context,includeSystembool) (int64,error) {
27832787
q.mutex.RLock()
@@ -9191,6 +9195,15 @@ func (q *FakeQuerier) InsertPresetParameters(_ context.Context, arg database.Ins
91919195
returnpresetParameters,nil
91929196
}
91939197

9198+
func (q*FakeQuerier)InsertPresetPrebuildSchedule(ctx context.Context,arg database.InsertPresetPrebuildScheduleParams) (database.TemplateVersionPresetPrebuildSchedule,error) {
9199+
err:=validateDatabaseType(arg)
9200+
iferr!=nil {
9201+
return database.TemplateVersionPresetPrebuildSchedule{},err
9202+
}
9203+
9204+
return database.TemplateVersionPresetPrebuildSchedule{},ErrUnimplemented
9205+
}
9206+
91949207
func (q*FakeQuerier)InsertProvisionerJob(_ context.Context,arg database.InsertProvisionerJobParams) (database.ProvisionerJob,error) {
91959208
iferr:=validateDatabaseType(arg);err!=nil {
91969209
return database.ProvisionerJob{},err

‎coderd/database/dbmetrics/querymetrics.go

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

‎coderd/database/dbmock/dbmock.go

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

‎coderd/database/dump.sql

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/foreign_key_constraint.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Drop the prebuild schedules table
2+
DROPTABLE template_version_preset_prebuild_schedules;
3+
4+
-- Remove scheduling_timezone column from template_version_presets table
5+
ALTERTABLE template_version_presets
6+
DROP COLUMN scheduling_timezone;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- Add scheduling_timezone column to template_version_presets table
2+
ALTERTABLE template_version_presets
3+
ADD COLUMN scheduling_timezoneTEXT DEFAULT''NOT NULL;
4+
5+
-- Add table for prebuild schedules
6+
CREATETABLEtemplate_version_preset_prebuild_schedules (
7+
id UUIDPRIMARY KEY DEFAULT gen_random_uuid()NOT NULL,
8+
preset_id UUIDNOT NULL,
9+
cron_expressionTEXTNOT NULL,
10+
desired_instancesINTEGERNOT NULL,
11+
FOREIGN KEY (preset_id)REFERENCES template_version_presets (id)ON DELETE CASCADE
12+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
INSERT INTO
2+
template_version_preset_prebuild_schedules (
3+
id,
4+
preset_id,
5+
cron_expression,
6+
desired_instances
7+
)
8+
VALUES (
9+
'e387cac1-9bf1-4fb6-8a34-db8cfb750dd0',
10+
'28b42cc0-c4fe-4907-a0fe-e4d20f1e9bfe',
11+
'* 8-18 * * 1-5',
12+
1
13+
);

‎coderd/database/models.go

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

‎coderd/database/querier.go

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp