MCPcopy Index your code
hub / github.com/coder/coder / waitForTaskIdle

Function waitForTaskIdle

cli/task_send.go:130–224  ·  view source on GitHub ↗

waitForTaskIdle optionally watches a workspace build to completion, then polls until the task becomes active and its app state is idle. This merges build-watching and idle-polling into a single loop so that status changes (e.g. paused) are never missed between phases.

(ctx context.Context, inv *serpent.Invocation, clk quartz.Clock, client *codersdk.Client, task codersdk.Task, workspaceBuildID uuid.UUID)

Source from the content-addressed store, hash-verified

128// This merges build-watching and idle-polling into a single loop so
129// that status changes (e.g. paused) are never missed between phases.
130func waitForTaskIdle(ctx context.Context, inv *serpent.Invocation, clk quartz.Clock, client *codersdk.Client, task codersdk.Task, workspaceBuildID uuid.UUID) error {
131 if workspaceBuildID != uuid.Nil {
132 if err := cliui.WorkspaceBuild(ctx, inv.Stdout, client, workspaceBuildID); err != nil {
133 return xerrors.Errorf("watch workspace build: %w", err)
134 }
135 }
136
137 cliui.Infof(inv.Stdout, "Waiting for task to become idle...")
138
139 // NOTE(DanielleMaywood):
140 // It has been observed that the `TaskStatusError` state has
141 // appeared during a typical healthy startup [^0]. To combat
142 // this, we allow a 5 minute grace period where we allow
143 // `TaskStatusError` to surface without immediately failing.
144 //
145 // TODO(DanielleMaywood):
146 // Remove this grace period once the upstream agentapi health
147 // check no longer reports transient error states during normal
148 // startup.
149 //
150 // [0]: https://github.com/coder/coder/pull/22203#discussion_r2858002569
151 const errorGracePeriod = 5 * time.Minute
152 gracePeriodDeadline := time.Now().Add(errorGracePeriod)
153
154 // NOTE(DanielleMaywood):
155 // On resume the MCP may not report an initial app status,
156 // leaving CurrentState nil indefinitely. To avoid hanging
157 // forever we treat Active with nil CurrentState as idle
158 // after a grace period, giving the MCP time to report
159 // during normal startup.
160 const nilStateGracePeriod = 30 * time.Second
161 var nilStateDeadline time.Time
162
163 // TODO(DanielleMaywood):
164 // When we have a streaming Task API, this should be converted
165 // away from polling.
166 const pollInterval = 5 * time.Second
167 ticker := clk.NewTicker(time.Nanosecond, "task_send", "poll")
168 defer ticker.Stop()
169 for {
170 select {
171 case <-ctx.Done():
172 return ctx.Err()
173 case <-ticker.C:
174 ticker.Reset(pollInterval, "task_send", "poll")
175 task, err := client.TaskByID(ctx, task.ID)
176 if err != nil {
177 return xerrors.Errorf("get task by id: %w", err)
178 }
179
180 switch task.Status {
181 case codersdk.TaskStatusInitializing,
182 codersdk.TaskStatusPending:
183 // Not yet active, keep polling.
184 continue
185 case codersdk.TaskStatusActive:
186 // Task is active; check app state.
187 if task.CurrentState == nil {

Callers 1

taskSendMethod · 0.85

Calls 10

WorkspaceBuildFunction · 0.92
InfofFunction · 0.92
ErrMethod · 0.80
TaskByIDMethod · 0.80
AddMethod · 0.65
StopMethod · 0.65
ResetMethod · 0.65
ErrorfMethod · 0.45
DoneMethod · 0.45
IsZeroMethod · 0.45

Tested by

no test coverage detected