mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
feat: allow bumping workspace deadline (#1828)
* Adds a `bump` command to extend workspace build deadline * Reduces WARN-level logging spam from autobuild executor * Modifies `cli/ssh` notifications to read from workspace build deadline and to notify relative time instead (sidestepping the problem of figuring out a user's timezone across multiple OSes) * Shows workspace extension time in `coder list` output e.g. ``` WORKSPACE TEMPLATE STATUS LAST BUILT OUTDATED AUTOSTART TTL developer/test1 docker Running 4m false 0 9 * * MON-FRI 15m (+5m) ```
This commit is contained in:
@ -88,7 +88,7 @@ func (e *Executor) runOnce(t time.Time) error {
|
||||
}
|
||||
|
||||
if !priorJob.CompletedAt.Valid || priorJob.Error.String != "" {
|
||||
e.log.Warn(e.ctx, "last workspace build did not complete successfully, skipping",
|
||||
e.log.Debug(e.ctx, "last workspace build did not complete successfully, skipping",
|
||||
slog.F("workspace_id", ws.ID),
|
||||
slog.F("error", priorJob.Error.String),
|
||||
)
|
||||
@ -107,13 +107,14 @@ func (e *Executor) runOnce(t time.Time) error {
|
||||
)
|
||||
continue
|
||||
}
|
||||
// Truncate to nearest minute for consistency with autostart behavior
|
||||
nextTransition = priorHistory.Deadline.Truncate(time.Minute)
|
||||
// For stopping, do not truncate. This is inconsistent with autostart, but
|
||||
// it ensures we will not stop too early.
|
||||
nextTransition = priorHistory.Deadline
|
||||
case database.WorkspaceTransitionStop:
|
||||
validTransition = database.WorkspaceTransitionStart
|
||||
sched, err := schedule.Weekly(ws.AutostartSchedule.String)
|
||||
if err != nil {
|
||||
e.log.Warn(e.ctx, "workspace has invalid autostart schedule, skipping",
|
||||
e.log.Debug(e.ctx, "workspace has invalid autostart schedule, skipping",
|
||||
slog.F("workspace_id", ws.ID),
|
||||
slog.F("autostart_schedule", ws.AutostartSchedule.String),
|
||||
)
|
||||
|
@ -550,7 +550,7 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr
|
||||
workspace, err := db.GetWorkspaceByID(ctx, workspaceBuild.WorkspaceID)
|
||||
if err == nil {
|
||||
if workspace.Ttl.Valid {
|
||||
workspaceDeadline = now.Add(time.Duration(workspace.Ttl.Int64)).Truncate(time.Minute)
|
||||
workspaceDeadline = now.Add(time.Duration(workspace.Ttl.Int64))
|
||||
}
|
||||
} else {
|
||||
// Huh? Did the workspace get deleted?
|
||||
|
@ -604,7 +604,7 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
return xerrors.Errorf("workspace must be started, current status: %s", build.Transition)
|
||||
}
|
||||
|
||||
newDeadline := req.Deadline.Truncate(time.Minute).UTC()
|
||||
newDeadline := req.Deadline.UTC()
|
||||
if newDeadline.IsZero() {
|
||||
// This should not be possible because the struct validation field enforces a non-zero value.
|
||||
code = http.StatusBadRequest
|
||||
@ -616,8 +616,8 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {
|
||||
return xerrors.Errorf("new deadline %q must be after existing deadline %q", newDeadline.Format(time.RFC3339), build.Deadline.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
// both newDeadline and build.Deadline are truncated to time.Minute
|
||||
if newDeadline == build.Deadline {
|
||||
// Disallow updates within less than one minute
|
||||
if withinDuration(newDeadline, build.Deadline, time.Minute) {
|
||||
code = http.StatusNotModified
|
||||
return nil
|
||||
}
|
||||
@ -786,6 +786,7 @@ func convertWorkspaces(ctx context.Context, db database.Store, workspaces []data
|
||||
InitiatorID: workspaceBuild.InitiatorID,
|
||||
ProvisionerState: workspaceBuild.ProvisionerState,
|
||||
JobID: workspaceBuild.JobID,
|
||||
Deadline: workspaceBuild.Deadline,
|
||||
}
|
||||
}
|
||||
templateByID := map[uuid.UUID]database.Template{}
|
||||
@ -848,3 +849,12 @@ func convertSQLNullInt64(i sql.NullInt64) *time.Duration {
|
||||
|
||||
return (*time.Duration)(&i.Int64)
|
||||
}
|
||||
|
||||
func withinDuration(t1, t2 time.Time, d time.Duration) bool {
|
||||
dt := t1.Sub(t2)
|
||||
if dt < -d || dt > d {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
Reference in New Issue
Block a user