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

Method handleConnected

cli/cliui/agent.go:192–266  ·  view source on GitHub ↗

handleConnected handles the Connected state and startup script logic. This is a terminal state, returns nil on success or error on failure. nolint:revive // Control flag is acceptable for internal method.

(ctx context.Context, agent codersdk.WorkspaceAgent, showStartupLogs bool, fetchedAgent chan fetchAgentResult)

Source from the content-addressed store, hash-verified

190//
191//nolint:revive // Control flag is acceptable for internal method.
192func (aw *agentWaiter) handleConnected(ctx context.Context, agent codersdk.WorkspaceAgent, showStartupLogs bool, fetchedAgent chan fetchAgentResult) error {
193 if !showStartupLogs && agent.LifecycleState == codersdk.WorkspaceAgentLifecycleReady {
194 // The workspace is ready, there's nothing to do but connect.
195 return nil
196 }
197
198 // Determine if we should follow/stream logs (blocking mode).
199 follow := aw.opts.Wait && agent.LifecycleState.Starting()
200
201 stage := "Running workspace agent startup scripts"
202 if !follow {
203 stage += " (non-blocking)"
204 }
205 aw.sw.Start(stage)
206
207 if follow {
208 aw.sw.Log(time.Time{}, codersdk.LogLevelInfo, "==> ℹ︎ To connect immediately, reconnect with --wait=no or CODER_SSH_WAIT=no, see --help for more information.")
209 }
210
211 // In non-blocking mode (Wait=false), we don't stream logs. This prevents
212 // dumping a wall of logs on users who explicitly pass --wait=no. The stage
213 // indicator is still shown, just not the log content. See issue #13580.
214 if aw.opts.Wait {
215 var err error
216 agent, err = aw.streamLogs(ctx, agent, follow, fetchedAgent)
217 if err != nil {
218 return err
219 }
220
221 // If we were following, wait until startup completes.
222 if follow {
223 agent, err = aw.pollWhile(ctx, agent, func(agent codersdk.WorkspaceAgent) bool {
224 return agent.LifecycleState.Starting()
225 })
226 if err != nil {
227 return err
228 }
229 }
230 }
231
232 // Handle final lifecycle state.
233 switch agent.LifecycleState {
234 case codersdk.WorkspaceAgentLifecycleReady:
235 aw.sw.Complete(stage, safeDuration(aw.sw, agent.ReadyAt, agent.StartedAt))
236 case codersdk.WorkspaceAgentLifecycleStartTimeout:
237 // Backwards compatibility: Avoid printing warning if
238 // coderd is old and doesn't set ReadyAt for timeouts.
239 if agent.ReadyAt == nil {
240 aw.sw.Fail(stage, 0)
241 } else {
242 aw.sw.Fail(stage, safeDuration(aw.sw, agent.ReadyAt, agent.StartedAt))
243 }
244 aw.sw.Log(time.Time{}, codersdk.LogLevelWarn, "Warning: A startup script timed out and your workspace may be incomplete.")
245 case codersdk.WorkspaceAgentLifecycleStartError:
246 aw.sw.Fail(stage, safeDuration(aw.sw, agent.ReadyAt, agent.StartedAt))
247 aw.sw.Log(time.Time{}, codersdk.LogLevelWarn, "Warning: A startup script exited with an error and your workspace may be incomplete.")
248 aw.sw.Log(time.Time{}, codersdk.LogLevelWarn, troubleshootingMessage(agent, fmt.Sprintf("%s/admin/templates/troubleshooting#startup-script-exited-with-an-error", aw.opts.DocsURL)))
249 default:

Callers 1

waitMethod · 0.95

Calls 10

streamLogsMethod · 0.95
pollWhileMethod · 0.95
safeDurationFunction · 0.85
troubleshootingMessageFunction · 0.85
LogMethod · 0.80
ShuttingDownMethod · 0.80
StartMethod · 0.65
StartingMethod · 0.45
CompleteMethod · 0.45
FailMethod · 0.45

Tested by

no test coverage detected