mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: prevent activity bump for prebuilt workspaces (#19263)
## Description
This PR ensures that activity-based deadline extensions ("activity
bumping") are not applied to prebuilt workspaces. Prebuilds are managed
by the reconciliation loop and must not have `deadline` or
`max_deadline` values set or extended, as they are not part of the
regular lifecycle executor path.
## Changes
- Update `ActivityBumpWorkspace` SQL query to discard prebuilt
workspaces
- Update application layer to avoid calling activity bump logic on
prebuilt workspaces
Related with:
* Issue: https://github.com/coder/coder/issues/18898
* PR: https://github.com/coder/coder/pull/19252
This commit is contained in:
@@ -32,7 +32,7 @@ WITH latest AS (
|
||||
-- be as if the workspace auto started at the given time and the
|
||||
-- original TTL was applied.
|
||||
--
|
||||
-- Sadly we can't define ` + "`" + `activity_bump_interval` + "`" + ` above since
|
||||
-- Sadly we can't define 'activity_bump_interval' above since
|
||||
-- it won't be available for this CASE statement, so we have to
|
||||
-- copy the cast twice.
|
||||
WHEN NOW() + (templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval > $1 :: timestamptz
|
||||
@@ -62,7 +62,11 @@ WITH latest AS (
|
||||
ON workspaces.id = workspace_builds.workspace_id
|
||||
JOIN templates
|
||||
ON templates.id = workspaces.template_id
|
||||
WHERE workspace_builds.workspace_id = $2::uuid
|
||||
WHERE
|
||||
workspace_builds.workspace_id = $2::uuid
|
||||
-- Prebuilt workspaces (identified by having the prebuilds system user as owner_id)
|
||||
-- are managed by the reconciliation loop and not subject to activity bumping
|
||||
AND workspaces.owner_id != 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID
|
||||
ORDER BY workspace_builds.build_number DESC
|
||||
LIMIT 1
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ WITH latest AS (
|
||||
-- be as if the workspace auto started at the given time and the
|
||||
-- original TTL was applied.
|
||||
--
|
||||
-- Sadly we can't define `activity_bump_interval` above since
|
||||
-- Sadly we can't define 'activity_bump_interval' above since
|
||||
-- it won't be available for this CASE statement, so we have to
|
||||
-- copy the cast twice.
|
||||
WHEN NOW() + (templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval > @next_autostart :: timestamptz
|
||||
@@ -52,7 +52,11 @@ WITH latest AS (
|
||||
ON workspaces.id = workspace_builds.workspace_id
|
||||
JOIN templates
|
||||
ON templates.id = workspaces.template_id
|
||||
WHERE workspace_builds.workspace_id = @workspace_id::uuid
|
||||
WHERE
|
||||
workspace_builds.workspace_id = @workspace_id::uuid
|
||||
-- Prebuilt workspaces (identified by having the prebuilds system user as owner_id)
|
||||
-- are managed by the reconciliation loop and not subject to activity bumping
|
||||
AND workspaces.owner_id != 'c42fdf75-3097-471c-8c33-fb52454d81c0'::UUID
|
||||
ORDER BY workspace_builds.build_number DESC
|
||||
LIMIT 1
|
||||
)
|
||||
|
||||
@@ -149,33 +149,36 @@ func (r *Reporter) ReportAgentStats(ctx context.Context, now time.Time, workspac
|
||||
return nil
|
||||
}
|
||||
|
||||
// check next autostart
|
||||
var nextAutostart time.Time
|
||||
if workspace.AutostartSchedule.String != "" {
|
||||
templateSchedule, err := (*(r.opts.TemplateScheduleStore.Load())).Get(ctx, r.opts.Database, workspace.TemplateID)
|
||||
// If the template schedule fails to load, just default to bumping
|
||||
// without the next transition and log it.
|
||||
switch {
|
||||
case err == nil:
|
||||
next, allowed := schedule.NextAutostart(now, workspace.AutostartSchedule.String, templateSchedule)
|
||||
if allowed {
|
||||
nextAutostart = next
|
||||
// Prebuilds are not subject to activity-based deadline bumps
|
||||
if !workspace.IsPrebuild() {
|
||||
// check next autostart
|
||||
var nextAutostart time.Time
|
||||
if workspace.AutostartSchedule.String != "" {
|
||||
templateSchedule, err := (*(r.opts.TemplateScheduleStore.Load())).Get(ctx, r.opts.Database, workspace.TemplateID)
|
||||
// If the template schedule fails to load, just default to bumping
|
||||
// without the next transition and log it.
|
||||
switch {
|
||||
case err == nil:
|
||||
next, allowed := schedule.NextAutostart(now, workspace.AutostartSchedule.String, templateSchedule)
|
||||
if allowed {
|
||||
nextAutostart = next
|
||||
}
|
||||
case database.IsQueryCanceledError(err):
|
||||
r.opts.Logger.Debug(ctx, "query canceled while loading template schedule",
|
||||
slog.F("workspace_id", workspace.ID),
|
||||
slog.F("template_id", workspace.TemplateID))
|
||||
default:
|
||||
r.opts.Logger.Error(ctx, "failed to load template schedule bumping activity, defaulting to bumping by 60min",
|
||||
slog.F("workspace_id", workspace.ID),
|
||||
slog.F("template_id", workspace.TemplateID),
|
||||
slog.Error(err),
|
||||
)
|
||||
}
|
||||
case database.IsQueryCanceledError(err):
|
||||
r.opts.Logger.Debug(ctx, "query canceled while loading template schedule",
|
||||
slog.F("workspace_id", workspace.ID),
|
||||
slog.F("template_id", workspace.TemplateID))
|
||||
default:
|
||||
r.opts.Logger.Error(ctx, "failed to load template schedule bumping activity, defaulting to bumping by 60min",
|
||||
slog.F("workspace_id", workspace.ID),
|
||||
slog.F("template_id", workspace.TemplateID),
|
||||
slog.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// bump workspace activity
|
||||
ActivityBumpWorkspace(ctx, r.opts.Logger.Named("activity_bump"), r.opts.Database, workspace.ID, nextAutostart)
|
||||
// bump workspace activity
|
||||
ActivityBumpWorkspace(ctx, r.opts.Logger.Named("activity_bump"), r.opts.Database, workspace.ID, nextAutostart)
|
||||
}
|
||||
|
||||
// bump workspace last_used_at
|
||||
r.opts.UsageTracker.Add(workspace.ID)
|
||||
|
||||
Reference in New Issue
Block a user