mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: make GetWorkspacesEligibleForTransition return less false-positives (#15429)
Relates to https://github.com/coder/coder/issues/15082 The old implementation of `GetWorkspacesEligibleForTransition` returns many workspaces that are not actually eligible for transition. This new implementation reduces this number significantly (at least on our dogfood instance).
This commit is contained in:
@@ -6868,60 +6868,99 @@ func (q *FakeQuerier) GetWorkspacesAndAgentsByOwnerID(ctx context.Context, owner
|
||||
return q.GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx, ownerID, nil)
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.WorkspaceTable, error) {
|
||||
func (q *FakeQuerier) GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]database.GetWorkspacesEligibleForTransitionRow, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
workspaces := []database.WorkspaceTable{}
|
||||
workspaces := []database.GetWorkspacesEligibleForTransitionRow{}
|
||||
for _, workspace := range q.workspaces {
|
||||
build, err := q.getLatestWorkspaceBuildByWorkspaceIDNoLock(ctx, workspace.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if build.Transition == database.WorkspaceTransitionStart &&
|
||||
!build.Deadline.IsZero() &&
|
||||
build.Deadline.Before(now) &&
|
||||
!workspace.DormantAt.Valid {
|
||||
workspaces = append(workspaces, workspace)
|
||||
continue
|
||||
}
|
||||
|
||||
if build.Transition == database.WorkspaceTransitionStop &&
|
||||
workspace.AutostartSchedule.Valid &&
|
||||
!workspace.DormantAt.Valid {
|
||||
workspaces = append(workspaces, workspace)
|
||||
continue
|
||||
}
|
||||
|
||||
job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get provisioner job by ID: %w", err)
|
||||
}
|
||||
if codersdk.ProvisionerJobStatus(job.JobStatus) == codersdk.ProvisionerJobFailed {
|
||||
workspaces = append(workspaces, workspace)
|
||||
continue
|
||||
}
|
||||
|
||||
template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get template by ID: %w", err)
|
||||
}
|
||||
if !workspace.DormantAt.Valid && template.TimeTilDormant > 0 {
|
||||
workspaces = append(workspaces, workspace)
|
||||
continue
|
||||
}
|
||||
if workspace.DormantAt.Valid && template.TimeTilDormantAutoDelete > 0 {
|
||||
workspaces = append(workspaces, workspace)
|
||||
continue
|
||||
return nil, xerrors.Errorf("get workspace build by ID: %w", err)
|
||||
}
|
||||
|
||||
user, err := q.getUserByIDNoLock(workspace.OwnerID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get user by ID: %w", err)
|
||||
}
|
||||
if user.Status == database.UserStatusSuspended && build.Transition == database.WorkspaceTransitionStart {
|
||||
workspaces = append(workspaces, workspace)
|
||||
|
||||
job, err := q.getProvisionerJobByIDNoLock(ctx, build.JobID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get provisioner job by ID: %w", err)
|
||||
}
|
||||
|
||||
template, err := q.getTemplateByIDNoLock(ctx, workspace.TemplateID)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("get template by ID: %w", err)
|
||||
}
|
||||
|
||||
if workspace.Deleted {
|
||||
continue
|
||||
}
|
||||
|
||||
if job.JobStatus != database.ProvisionerJobStatusFailed &&
|
||||
!workspace.DormantAt.Valid &&
|
||||
build.Transition == database.WorkspaceTransitionStart &&
|
||||
(user.Status == database.UserStatusSuspended || (!build.Deadline.IsZero() && build.Deadline.Before(now))) {
|
||||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{
|
||||
ID: workspace.ID,
|
||||
Name: workspace.Name,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if user.Status == database.UserStatusActive &&
|
||||
job.JobStatus != database.ProvisionerJobStatusFailed &&
|
||||
build.Transition == database.WorkspaceTransitionStop &&
|
||||
workspace.AutostartSchedule.Valid {
|
||||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{
|
||||
ID: workspace.ID,
|
||||
Name: workspace.Name,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if workspace.DormantAt.Valid &&
|
||||
workspace.DeletingAt.Valid &&
|
||||
workspace.DeletingAt.Time.Before(now) &&
|
||||
template.TimeTilDormantAutoDelete > 0 {
|
||||
if build.Transition == database.WorkspaceTransitionDelete &&
|
||||
job.JobStatus == database.ProvisionerJobStatusFailed {
|
||||
if job.CanceledAt.Valid && now.Sub(job.CanceledAt.Time) <= 24*time.Hour {
|
||||
continue
|
||||
}
|
||||
|
||||
if job.CompletedAt.Valid && now.Sub(job.CompletedAt.Time) <= 24*time.Hour {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{
|
||||
ID: workspace.ID,
|
||||
Name: workspace.Name,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
if template.FailureTTL > 0 &&
|
||||
build.Transition == database.WorkspaceTransitionStart &&
|
||||
job.JobStatus == database.ProvisionerJobStatusFailed &&
|
||||
job.CompletedAt.Valid &&
|
||||
now.Sub(job.CompletedAt.Time) > time.Duration(template.FailureTTL) {
|
||||
workspaces = append(workspaces, database.GetWorkspacesEligibleForTransitionRow{
|
||||
ID: workspace.ID,
|
||||
Name: workspace.Name,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user