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

Commit4f29df2

Browse files
add matchesCron
1 parent7549820 commit4f29df2

File tree

11 files changed

+145
-20
lines changed

11 files changed

+145
-20
lines changed

‎coderd/database/dbauthz/dbauthz.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2267,6 +2267,10 @@ func (q *querier) GetPresetParametersByTemplateVersionID(ctx context.Context, ar
22672267
returnq.db.GetPresetParametersByTemplateVersionID(ctx,args)
22682268
}
22692269

2270+
func (q*querier)GetPresetPrebuildSchedules(ctx context.Context) ([]database.TemplateVersionPresetPrebuildSchedule,error) {
2271+
panic("not implemented")
2272+
}
2273+
22702274
func (q*querier)GetPresetsAtFailureLimit(ctx context.Context,hardLimitint64) ([]database.GetPresetsAtFailureLimitRow,error) {
22712275
// GetPresetsAtFailureLimit returns a list of template version presets that have reached the hard failure limit.
22722276
// Request the same authorization permissions as GetPresetsBackoff, since the methods are similar.

‎coderd/database/dbmem/dbmem.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4369,6 +4369,10 @@ func (q *FakeQuerier) GetPresetParametersByTemplateVersionID(_ context.Context,
43694369
returnparameters,nil
43704370
}
43714371

4372+
func (q*FakeQuerier)GetPresetPrebuildSchedules(ctx context.Context) ([]database.TemplateVersionPresetPrebuildSchedule,error) {
4373+
panic("not implemented")
4374+
}
4375+
43724376
func (q*FakeQuerier)GetPresetsAtFailureLimit(ctx context.Context,hardLimitint64) ([]database.GetPresetsAtFailureLimitRow,error) {
43734377
returnnil,ErrUnimplemented
43744378
}

‎coderd/database/dbmetrics/querymetrics.go

Lines changed: 7 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: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

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

‎coderd/database/queries/prebuilds.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ SELECT
3535
tvp.id,
3636
tvp.name,
3737
tvp.desired_instancesAS desired_instances,
38+
tvp.autoscaling_enabled,
39+
tvp.autoscaling_timezone,
3840
tvp.invalidate_after_secsAS ttl,
3941
tvp.prebuild_status,
4042
t.deleted,

‎coderd/database/queries/presets.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,6 @@ SELECT tvp.*, tv.template_id, tv.organization_id FROM
8585
template_version_presets tvp
8686
INNER JOIN template_versions tvONtvp.template_version_id=tv.id
8787
WHEREtvp.id= @preset_id;
88+
89+
-- name: GetPresetPrebuildSchedules :many
90+
SELECT*FROM template_version_preset_prebuild_schedules;

‎coderd/prebuilds/global_snapshot.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
// GlobalSnapshot represents a full point-in-time snapshot of state relating to prebuilds across all templates.
1414
typeGlobalSnapshotstruct {
1515
Presets []database.GetTemplatePresetsWithPrebuildsRow
16+
PrebuildSchedules []database.TemplateVersionPresetPrebuildSchedule
1617
RunningPrebuilds []database.GetRunningPrebuiltWorkspacesRow
1718
PrebuildsInProgress []database.CountInProgressPrebuildsRow
1819
Backoffs []database.GetPresetsBackoffRow
@@ -21,6 +22,7 @@ type GlobalSnapshot struct {
2122

2223
funcNewGlobalSnapshot(
2324
presets []database.GetTemplatePresetsWithPrebuildsRow,
25+
prebuildSchedules []database.TemplateVersionPresetPrebuildSchedule,
2426
runningPrebuilds []database.GetRunningPrebuiltWorkspacesRow,
2527
prebuildsInProgress []database.CountInProgressPrebuildsRow,
2628
backoffs []database.GetPresetsBackoffRow,
@@ -33,6 +35,7 @@ func NewGlobalSnapshot(
3335

3436
returnGlobalSnapshot{
3537
Presets:presets,
38+
PrebuildSchedules:prebuildSchedules,
3639
RunningPrebuilds:runningPrebuilds,
3740
PrebuildsInProgress:prebuildsInProgress,
3841
Backoffs:backoffs,
@@ -48,6 +51,10 @@ func (s GlobalSnapshot) FilterByPreset(presetID uuid.UUID) (*PresetSnapshot, err
4851
returnnil,xerrors.Errorf("no preset found with ID %q",presetID)
4952
}
5053

54+
prebuildSchedules:=slice.Filter(s.PrebuildSchedules,func(preset database.TemplateVersionPresetPrebuildSchedule)bool {
55+
returnpreset.ID==presetID
56+
})
57+
5158
// Only include workspaces that have successfully started
5259
running:=slice.Filter(s.RunningPrebuilds,func(prebuild database.GetRunningPrebuiltWorkspacesRow)bool {
5360
if!prebuild.CurrentPresetID.Valid {
@@ -74,12 +81,13 @@ func (s GlobalSnapshot) FilterByPreset(presetID uuid.UUID) (*PresetSnapshot, err
7481
_,isHardLimited:=s.HardLimitedPresetsMap[preset.ID]
7582

7683
return&PresetSnapshot{
77-
Preset:preset,
78-
Running:nonExpired,
79-
Expired:expired,
80-
InProgress:inProgress,
81-
Backoff:backoffPtr,
82-
IsHardLimited:isHardLimited,
84+
Preset:preset,
85+
PrebuildSchedules:prebuildSchedules,
86+
Running:nonExpired,
87+
Expired:expired,
88+
InProgress:inProgress,
89+
Backoff:backoffPtr,
90+
IsHardLimited:isHardLimited,
8391
},nil
8492
}
8593

‎coderd/prebuilds/preset_snapshot.go

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package prebuilds
22

33
import (
4+
"github.com/coder/coder/v2/coderd/schedule/cron"
5+
"golang.org/x/xerrors"
46
"slices"
57
"time"
68

@@ -36,12 +38,13 @@ const (
3638
// - InProgress: prebuilds currently in progress
3739
// - Backoff: holds failure info to decide if prebuild creation should be backed off
3840
typePresetSnapshotstruct {
39-
Preset database.GetTemplatePresetsWithPrebuildsRow
40-
Running []database.GetRunningPrebuiltWorkspacesRow
41-
Expired []database.GetRunningPrebuiltWorkspacesRow
42-
InProgress []database.CountInProgressPrebuildsRow
43-
Backoff*database.GetPresetsBackoffRow
44-
IsHardLimitedbool
41+
Preset database.GetTemplatePresetsWithPrebuildsRow
42+
PrebuildSchedules []database.TemplateVersionPresetPrebuildSchedule
43+
Running []database.GetRunningPrebuiltWorkspacesRow
44+
Expired []database.GetRunningPrebuiltWorkspacesRow
45+
InProgress []database.CountInProgressPrebuildsRow
46+
Backoff*database.GetPresetsBackoffRow
47+
IsHardLimitedbool
4548
}
4649

4750
// ReconciliationState represents the processed state of a preset's prebuilds,
@@ -83,6 +86,43 @@ func (ra *ReconciliationActions) IsNoop() bool {
8386
returnra.Create==0&&len(ra.DeleteIDs)==0&&ra.BackoffUntil.IsZero()
8487
}
8588

89+
// matchesCron checks if the given time matches the cron expression
90+
// Assumes the time is already in the correct timezone
91+
funcmatchesCron(cronExpressionstring,now time.Time) (bool,error) {
92+
sched,err:=cron.Weekly(cronExpression)
93+
iferr!=nil {
94+
returnfalse,xerrors.Errorf("failed to parse cron expression: %w",err)
95+
}
96+
97+
returnsched.IsWithinRange(now),nil
98+
}
99+
100+
func (pPresetSnapshot)calculateDesiredInstances(now time.Time) (int32,error) {
101+
if!p.Preset.AutoscalingEnabled {
102+
returnp.Preset.DesiredInstances.Int32,nil
103+
}
104+
105+
loc,err:=time.LoadLocation(p.Preset.AutoscalingTimezone)
106+
iferr!=nil {
107+
return0,xerrors.Errorf("can't parse location %v: %w",p.Preset.AutoscalingTimezone,err)
108+
}
109+
110+
now=now.In(loc)
111+
112+
// Check each schedule
113+
for_,schedule:=rangep.PrebuildSchedules {
114+
matches,err:=matchesCron(schedule.CronExpression,now)
115+
iferr!=nil {
116+
return0,xerrors.Errorf("failed to match cron expression: %w",err)
117+
}
118+
ifmatches {
119+
returnschedule.Instances,nil
120+
}
121+
}
122+
123+
returnp.Preset.DesiredInstances.Int32,nil
124+
}
125+
86126
// CalculateState computes the current state of prebuilds for a preset, including:
87127
// - Actual: Number of currently running prebuilds, i.e., non-expired and expired prebuilds
88128
// - Expired: Number of currently running expired prebuilds
@@ -111,7 +151,10 @@ func (p PresetSnapshot) CalculateState() *ReconciliationState {
111151
expired=int32(len(p.Expired))
112152

113153
ifp.isActive() {
114-
desired=p.Preset.DesiredInstances.Int32
154+
desired,err:=p.calculateDesiredInstances(time.Now())
155+
iferr!=nil {
156+
// TODO: handle error
157+
}
115158
eligible=p.countEligible()
116159
extraneous=max(actual-expired-desired,0)
117160
}

‎coderd/schedule/cron/cron.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,14 @@ func (s Schedule) Next(t time.Time) time.Time {
155155
returns.sched.Next(t)
156156
}
157157

158+
func (sSchedule)IsWithinRange(t time.Time)bool {
159+
// Get the next scheduled time
160+
next:=s.Next(t)
161+
162+
// If the next time is more than a minute away, we're not within range
163+
returnnext.Sub(t)<=time.Minute
164+
}
165+
158166
var (
159167
t0=time.Date(1970,1,1,1,1,1,0,time.UTC)
160168
tMax=t0.Add(168*time.Hour)

‎enterprise/coderd/prebuilds/reconcile.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,11 @@ func (c *StoreReconciler) SnapshotState(ctx context.Context, store database.Stor
360360
returnnil
361361
}
362362

363+
presetPrebuildSchedules,err:=db.GetPresetPrebuildSchedules(ctx)
364+
iferr!=nil {
365+
returnxerrors.Errorf("failed to get preset prebuild schedules: %w",err)
366+
}
367+
363368
allRunningPrebuilds,err:=db.GetRunningPrebuiltWorkspaces(ctx)
364369
iferr!=nil {
365370
returnxerrors.Errorf("failed to get running prebuilds: %w",err)
@@ -382,6 +387,7 @@ func (c *StoreReconciler) SnapshotState(ctx context.Context, store database.Stor
382387

383388
state=prebuilds.NewGlobalSnapshot(
384389
presetsWithPrebuilds,
390+
presetPrebuildSchedules,
385391
allRunningPrebuilds,
386392
allPrebuildsInProgress,
387393
presetsBackoff,
@@ -602,13 +608,14 @@ func (c *StoreReconciler) executeReconciliationAction(ctx context.Context, logge
602608
// Unexpected things happen (i.e. bugs or bitflips); let's defend against disastrous outcomes.
603609
// See https://blog.robertelder.org/causes-of-bit-flips-in-computer-memory/.
604610
// This is obviously not comprehensive protection against this sort of problem, but this is one essential check.
605-
desired:=ps.Preset.DesiredInstances.Int32
606-
ifaction.Create>desired {
607-
logger.Critical(ctx,"determined excessive count of prebuilds to create; clamping to desired count",
608-
slog.F("create_count",action.Create),slog.F("desired_count",desired))
609-
610-
action.Create=desired
611-
}
611+
// TODO: uncomment:
612+
//desired := ps.Preset.DesiredInstances.Int32
613+
//if action.Create > desired {
614+
//logger.Critical(ctx, "determined excessive count of prebuilds to create; clamping to desired count",
615+
//slog.F("create_count", action.Create), slog.F("desired_count", desired))
616+
//
617+
//action.Create = desired
618+
//}
612619

613620
// If preset is hard-limited, and it's a create operation, log it and exit early.
614621
// Creation operation is disallowed for hard-limited preset.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp