-
Notifications
You must be signed in to change notification settings - Fork 988
feat: allow disabling autostart and custom autostop for template #6933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a7e3bb0
02b02e0
2d18e96
b319b68
7b70ce4
903c12b
5a255d8
b02477d
ef26028
31f6177
2a7ddec
c22ef15
d825c92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package executor | |
import ( | ||
"context" | ||
"encoding/json" | ||
"sync/atomic" | ||
"time" | ||
|
||
"github.com/google/uuid" | ||
|
@@ -18,11 +19,12 @@ import ( | |
|
||
// Executor automatically starts or stops workspaces. | ||
type Executor struct { | ||
ctx context.Context | ||
db database.Store | ||
log slog.Logger | ||
tick <-chan time.Time | ||
statsCh chan<- Stats | ||
ctx context.Context | ||
db database.Store | ||
templateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore] | ||
log slog.Logger | ||
tick <-chan time.Time | ||
statsCh chan<- Stats | ||
} | ||
|
||
// Stats contains information about one run of Executor. | ||
|
@@ -33,13 +35,14 @@ type Stats struct { | |
} | ||
|
||
// New returns a new autobuild executor. | ||
func New(ctx context.Context, db database.Store, log slog.Logger, tick <-chan time.Time) *Executor { | ||
func New(ctx context.Context, db database.Store, tss *atomic.Pointer[schedule.TemplateScheduleStore], log slog.Logger, tick <-chan time.Time) *Executor { | ||
le := &Executor{ | ||
//nolint:gocritic // Autostart has a limited set of permissions. | ||
ctx: dbauthz.AsAutostart(ctx), | ||
db: db, | ||
tick: tick, | ||
log: log, | ||
ctx: dbauthz.AsAutostart(ctx), | ||
db: db, | ||
templateScheduleStore: tss, | ||
tick: tick, | ||
log: log, | ||
} | ||
return le | ||
} | ||
|
@@ -102,30 +105,20 @@ func (e *Executor) runOnce(t time.Time) Stats { | |
// NOTE: If a workspace build is created with a given TTL and then the user either | ||
// changes or unsets the TTL, the deadline for the workspace build will not | ||
// have changed. This behavior is as expected per #2229. | ||
workspaceRows, err := e.db.GetWorkspaces(e.ctx, database.GetWorkspacesParams{ | ||
Deleted: false, | ||
}) | ||
workspaces, err := e.db.GetWorkspacesEligibleForAutoStartStop(e.ctx, t) | ||
if err != nil { | ||
e.log.Error(e.ctx, "get workspaces for autostart or autostop", slog.Error(err)) | ||
return stats | ||
} | ||
workspaces := database.ConvertWorkspaceRows(workspaceRows) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
var eligibleWorkspaceIDs []uuid.UUID | ||
for _, ws := range workspaces { | ||
if isEligibleForAutoStartStop(ws) { | ||
eligibleWorkspaceIDs = append(eligibleWorkspaceIDs, ws.ID) | ||
} | ||
} | ||
|
||
// We only use errgroup here for convenience of API, not for early | ||
// cancellation. This means we only return nil errors in th eg.Go. | ||
eg := errgroup.Group{} | ||
// Limit the concurrency to avoid overloading the database. | ||
eg.SetLimit(10) | ||
|
||
for _, wsID := range eligibleWorkspaceIDs { | ||
wsID := wsID | ||
for _, ws := range workspaces { | ||
wsID := ws.ID | ||
log := e.log.With(slog.F("workspace_id", wsID)) | ||
|
||
eg.Go(func() error { | ||
|
@@ -137,9 +130,6 @@ func (e *Executor) runOnce(t time.Time) Stats { | |
log.Error(e.ctx, "get workspace autostart failed", slog.Error(err)) | ||
return nil | ||
} | ||
if !isEligibleForAutoStartStop(ws) { | ||
return nil | ||
} | ||
|
||
// Determine the workspace state based on its latest build. | ||
priorHistory, err := db.GetLatestWorkspaceBuildByWorkspaceID(e.ctx, ws.ID) | ||
|
@@ -148,6 +138,16 @@ func (e *Executor) runOnce(t time.Time) Stats { | |
return nil | ||
} | ||
|
||
templateSchedule, err := (*(e.templateScheduleStore.Load())).GetTemplateScheduleOptions(e.ctx, db, ws.TemplateID) | ||
if err != nil { | ||
log.Warn(e.ctx, "get template schedule options", slog.Error(err)) | ||
return nil | ||
} | ||
|
||
if !isEligibleForAutoStartStop(ws, priorHistory, templateSchedule) { | ||
return nil | ||
} | ||
|
||
priorJob, err := db.GetProvisionerJobByID(e.ctx, priorHistory.JobID) | ||
if err != nil { | ||
log.Warn(e.ctx, "get last provisioner job for workspace %q: %w", slog.Error(err)) | ||
|
@@ -198,8 +198,20 @@ func (e *Executor) runOnce(t time.Time) Stats { | |
return stats | ||
} | ||
|
||
func isEligibleForAutoStartStop(ws database.Workspace) bool { | ||
return !ws.Deleted && (ws.AutostartSchedule.String != "" || ws.Ttl.Int64 > 0) | ||
func isEligibleForAutoStartStop(ws database.Workspace, priorHistory database.WorkspaceBuild, templateSchedule schedule.TemplateScheduleOptions) bool { | ||
if ws.Deleted { | ||
return false | ||
} | ||
if templateSchedule.UserAutoStartEnabled && ws.AutostartSchedule.Valid && ws.AutostartSchedule.String != "" { | ||
return true | ||
} | ||
// Don't check the template schedule to see whether it allows autostop, this | ||
// is done during the build when determining the deadline. | ||
if priorHistory.Transition == database.WorkspaceTransitionStart && !priorHistory.Deadline.IsZero() { | ||
return true | ||
} | ||
|
||
return false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
|
||
func getNextTransition( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why did you remove this part?
Maybe I have to go through the entire review to find the answer...
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
executor.New
in the review.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this was a mistake, good catch to both of you. I removed this code and moved it somewhere else, and decided I wanted to move it back but forgot to put it back I guess.