deriveTaskCurrentState determines the current state of a task based on the workspace's latest app status and initialization phase. Returns nil if no valid state can be determined.
( dbTask database.Task, ws codersdk.Workspace, taskAgentLifecycle *codersdk.WorkspaceAgentLifecycle, taskAppHealth *codersdk.WorkspaceAppHealth, )
| 330 | // workspace's latest app status and initialization phase. |
| 331 | // Returns nil if no valid state can be determined. |
| 332 | func deriveTaskCurrentState( |
| 333 | dbTask database.Task, |
| 334 | ws codersdk.Workspace, |
| 335 | taskAgentLifecycle *codersdk.WorkspaceAgentLifecycle, |
| 336 | taskAppHealth *codersdk.WorkspaceAppHealth, |
| 337 | ) *codersdk.TaskStateEntry { |
| 338 | var currentState *codersdk.TaskStateEntry |
| 339 | |
| 340 | // Ignore 'latest app status' if it is older than the latest build and the |
| 341 | // latest build is a 'start' transition. This ensures that you don't show a |
| 342 | // stale app status from a previous build. For stop transitions, there is |
| 343 | // still value in showing the latest app status. |
| 344 | if ws.LatestAppStatus != nil { |
| 345 | if ws.LatestBuild.Transition != codersdk.WorkspaceTransitionStart || ws.LatestAppStatus.CreatedAt.After(ws.LatestBuild.CreatedAt) { |
| 346 | currentState = &codersdk.TaskStateEntry{ |
| 347 | Timestamp: ws.LatestAppStatus.CreatedAt, |
| 348 | State: appStatusStateToTaskState(ws.LatestAppStatus.State), |
| 349 | Message: ws.LatestAppStatus.Message, |
| 350 | URI: ws.LatestAppStatus.URI, |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | // If no valid agent state was found for the current build and the task is initializing, |
| 356 | // provide a descriptive initialization message. |
| 357 | if currentState == nil && dbTask.Status == database.TaskStatusInitializing { |
| 358 | message := "Initializing workspace" |
| 359 | |
| 360 | switch { |
| 361 | case ws.LatestBuild.Status == codersdk.WorkspaceStatusPending || |
| 362 | ws.LatestBuild.Status == codersdk.WorkspaceStatusStarting: |
| 363 | message = fmt.Sprintf("Workspace is %s", ws.LatestBuild.Status) |
| 364 | case taskAgentLifecycle != nil: |
| 365 | switch { |
| 366 | case *taskAgentLifecycle == codersdk.WorkspaceAgentLifecycleCreated: |
| 367 | message = "Agent is connecting" |
| 368 | case *taskAgentLifecycle == codersdk.WorkspaceAgentLifecycleStarting: |
| 369 | message = "Agent is starting" |
| 370 | case *taskAgentLifecycle == codersdk.WorkspaceAgentLifecycleReady: |
| 371 | if taskAppHealth != nil && *taskAppHealth == codersdk.WorkspaceAppHealthInitializing { |
| 372 | message = "App is initializing" |
| 373 | } else { |
| 374 | // In case the workspace app is not initializing, |
| 375 | // the overall task status should be updated accordingly |
| 376 | message = "Initializing workspace applications" |
| 377 | } |
| 378 | default: |
| 379 | // In case the workspace agent is not initializing, |
| 380 | // the overall task status should be updated accordingly |
| 381 | message = "Initializing workspace agent" |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | currentState = &codersdk.TaskStateEntry{ |
| 386 | Timestamp: ws.LatestBuild.CreatedAt, |
| 387 | State: codersdk.TaskStateWorking, |
| 388 | Message: message, |
| 389 | URI: "", |