- Notifications
You must be signed in to change notification settings - Fork1k
fix: make GetWorkspacesEligibleForTransition return even less false positives#15594
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
78d9bef
dea0c20
d0f1851
077439c
3b41985
1a66a14
9725ec7
5e9b806
b2a037b
997c902
dd05558
8bddfdf
66a01a3
b7434c0
100f54c
d201025
eac63b7
1b31cbb
eaf32ee
1599b2a
142e335
3f17e46
e993643
d349c56
a48fb99
cc93075
45350d1
c1648ae
03d0b7f
23b2ec9
18f3c8a
8b1b6d9
2d239a6
2e2f13a
df74e6f
dec3d6c
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -65,6 +65,7 @@ | ||
}, | ||
"automatic_updates": "never", | ||
"allow_renames": false, | ||
"favorite": false, | ||
"next_start_at": "[timestamp]" | ||
} | ||
] |
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -142,7 +142,7 @@ 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. | ||
workspaces, err := e.db.GetWorkspacesEligibleForTransition(e.ctx,currentTick) | ||
DanielleMaywood marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
if err != nil { | ||
e.log.Error(e.ctx, "get workspaces for autostart or autostop", slog.Error(err)) | ||
return stats | ||
@@ -205,6 +205,23 @@ func (e *Executor) runOnce(t time.Time) Stats { | ||
return xerrors.Errorf("get template scheduling options: %w", err) | ||
} | ||
// If next start at is not valid we need to re-compute it | ||
if !ws.NextStartAt.Valid && ws.AutostartSchedule.Valid { | ||
next, err := schedule.NextAllowedAutostart(currentTick, ws.AutostartSchedule.String, templateSchedule) | ||
if err == nil { | ||
nextStartAt := sql.NullTime{Valid: true, Time: dbtime.Time(next.UTC())} | ||
if err = tx.UpdateWorkspaceNextStartAt(e.ctx, database.UpdateWorkspaceNextStartAtParams{ | ||
ID: wsID, | ||
NextStartAt: nextStartAt, | ||
}); err != nil { | ||
return xerrors.Errorf("update workspace next start at: %w", err) | ||
} | ||
// Save re-fetching the workspace | ||
ws.NextStartAt = nextStartAt | ||
} | ||
} | ||
tmpl, err = tx.GetTemplateByID(e.ctx, ws.TemplateID) | ||
if err != nil { | ||
return xerrors.Errorf("get template by ID: %w", err) | ||
@@ -463,8 +480,8 @@ func isEligibleForAutostart(user database.User, ws database.Workspace, build dat | ||
return false | ||
} | ||
nextTransition,err := schedule.NextAllowedAutostart(build.CreatedAt, ws.AutostartSchedule.String, templateSchedule) | ||
iferr != nil { | ||
return false | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -475,6 +475,7 @@ func (q *FakeQuerier) convertToWorkspaceRowsNoLock(ctx context.Context, workspac | ||
DeletingAt: w.DeletingAt, | ||
AutomaticUpdates: w.AutomaticUpdates, | ||
Favorite: w.Favorite, | ||
NextStartAt: w.NextStartAt, | ||
OwnerAvatarUrl: extended.OwnerAvatarUrl, | ||
OwnerUsername: extended.OwnerUsername, | ||
@@ -1431,6 +1432,35 @@ func (q *FakeQuerier) BatchUpdateWorkspaceLastUsedAt(_ context.Context, arg data | ||
return nil | ||
} | ||
func (q *FakeQuerier) BatchUpdateWorkspaceNextStartAt(_ context.Context, arg database.BatchUpdateWorkspaceNextStartAtParams) error { | ||
err := validateDatabaseType(arg) | ||
if err != nil { | ||
return err | ||
} | ||
q.mutex.Lock() | ||
defer q.mutex.Unlock() | ||
for i, workspace := range q.workspaces { | ||
for j, workspaceID := range arg.IDs { | ||
if workspace.ID != workspaceID { | ||
continue | ||
} | ||
nextStartAt := arg.NextStartAts[j] | ||
if nextStartAt.IsZero() { | ||
q.workspaces[i].NextStartAt = sql.NullTime{} | ||
} else { | ||
q.workspaces[i].NextStartAt = sql.NullTime{Valid: true, Time: nextStartAt} | ||
} | ||
break | ||
} | ||
} | ||
return nil | ||
} | ||
func (*FakeQuerier) BulkMarkNotificationMessagesFailed(_ context.Context, arg database.BulkMarkNotificationMessagesFailedParams) (int64, error) { | ||
err := validateDatabaseType(arg) | ||
if err != nil { | ||
@@ -6908,6 +6938,20 @@ func (q *FakeQuerier) GetWorkspacesAndAgentsByOwnerID(ctx context.Context, owner | ||
return q.GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx, ownerID, nil) | ||
} | ||
func (q *FakeQuerier) GetWorkspacesByTemplateID(_ context.Context, templateID uuid.UUID) ([]database.WorkspaceTable, error) { | ||
q.mutex.RLock() | ||
defer q.mutex.RUnlock() | ||
workspaces := []database.WorkspaceTable{} | ||
for _, workspace := range q.workspaces { | ||
if workspace.TemplateID == templateID { | ||
workspaces = append(workspaces, workspace) | ||
} | ||
} | ||
return workspaces, nil | ||
} | ||
func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.GetWorkspacesEligibleForTransitionRow, error) { | ||
q.mutex.RLock() | ||
defer q.mutex.RUnlock() | ||
@@ -6952,7 +6996,13 @@ func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, no | ||
if user.Status == database.UserStatusActive && | ||
job.JobStatus != database.ProvisionerJobStatusFailed && | ||
build.Transition == database.WorkspaceTransitionStop && | ||
workspace.AutostartSchedule.Valid && | ||
// We do not know if workspace with a zero next start is eligible | ||
// for autostart, so we accept this false-positive. This can occur | ||
// when a coder version is upgraded and next_start_at has yet to | ||
// be set. | ||
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. We have a new known case, reset by db trigger. Should we implement the trigger in memory db as well? (I know it's probably going away soon, but still, might cause flakes?) 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. I don'tthink it'd cause flakes, but instead cause dbmem tests to fail when postgres tests do not. Happy to add it though 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. On second thought, I've checked 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. There is no good way to do it, just ad hoc code in various functions 😢 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. Ah that's unfortunate. I think attempting to emulate this trigger isn't worth it then. If someone writes a test that is dependent on the trigger (which they ideally shouldn't) then they'll have to disable it when running under | ||
(workspace.NextStartAt.Time.IsZero() || | ||
DanielleMaywood marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
!now.Before(workspace.NextStartAt.Time)) { | ||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ | ||
ID: workspace.ID, | ||
Name: workspace.Name, | ||
@@ -6962,7 +7012,7 @@ func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, no | ||
if !workspace.DormantAt.Valid && | ||
template.TimeTilDormant > 0 && | ||
now.Sub(workspace.LastUsedAt) >= time.Duration(template.TimeTilDormant) { | ||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{ | ||
ID: workspace.ID, | ||
Name: workspace.Name, | ||
@@ -7927,6 +7977,7 @@ func (q *FakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWork | ||
Ttl: arg.Ttl, | ||
LastUsedAt: arg.LastUsedAt, | ||
AutomaticUpdates: arg.AutomaticUpdates, | ||
NextStartAt: arg.NextStartAt, | ||
} | ||
q.workspaces = append(q.workspaces, workspace) | ||
return workspace, nil | ||
@@ -9868,6 +9919,7 @@ func (q *FakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.U | ||
continue | ||
} | ||
workspace.AutostartSchedule = arg.AutostartSchedule | ||
workspace.NextStartAt = arg.NextStartAt | ||
q.workspaces[index] = workspace | ||
return nil | ||
} | ||
@@ -10017,6 +10069,29 @@ func (q *FakeQuerier) UpdateWorkspaceLastUsedAt(_ context.Context, arg database. | ||
return sql.ErrNoRows | ||
} | ||
func (q *FakeQuerier) UpdateWorkspaceNextStartAt(_ context.Context, arg database.UpdateWorkspaceNextStartAtParams) error { | ||
err := validateDatabaseType(arg) | ||
if err != nil { | ||
return err | ||
} | ||
q.mutex.Lock() | ||
defer q.mutex.Unlock() | ||
for index, workspace := range q.workspaces { | ||
if workspace.ID != arg.ID { | ||
continue | ||
} | ||
workspace.NextStartAt = arg.NextStartAt | ||
q.workspaces[index] = workspace | ||
return nil | ||
} | ||
return sql.ErrNoRows | ||
} | ||
func (q *FakeQuerier) UpdateWorkspaceProxy(_ context.Context, arg database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) { | ||
q.mutex.Lock() | ||
defer q.mutex.Unlock() | ||
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.