Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: only create workspace agents for start builds - #28276

Merged
aslilac merged 10 commits into
mainfrom
lilac/no-agents-on-stop-builds
Aug 19, 2026
Merged

fix: only create workspace agents for start builds#28276
aslilac merged 10 commits into
mainfrom
lilac/no-agents-on-stop-builds

Conversation

@aslilac

@aslilac aslilac commented Aug 18, 2026

Copy link
Copy Markdown
Member

A stopped workspace could report an "unhealthy" agent.

Agents are attached to resources by walking the Terraform dependency graph upward from the coder_agent node. On a stop build the compute resource is usually gated by start_count and leaves state, but its graph node remains, so the walk can climb past it and land on a resource that persists across stop. The build then ships an agent that can never connect. Whether this happens at all depends on the shape of the graph, which is why it bites VM templates and not Kubernetes ones. examples/templates/digitalocean-linux reproduces it via digitalocean_project_resources.

Rather than make the graph walk smarter, agents are now only created for start builds. A stop or delete build has no running agents by definition, and the database already assumed this: external agent tokens are only returned for workspaces whose latest build is a start build.

Resources themselves are still recorded for every transition, so stopped workspaces keep listing their persistent resources.

Also fixes a latent bug this surfaced: task workspace apps were linked to app rows owned by the phantom stop-build agent. Paused tasks read logs from snapshots and reject sends, so nothing legitimately consumed that link. It is now left empty for non-start builds, which the surrounding code already handles.

Implementation plan and rejected alternatives

Problem

Agents are attached to resources by walking the Terraform dependency graph upward from the coder_agent node to the nearest managed non-coder_ resource (provisioner/terraform/resources.go, findResourcesInGraph). During a stop build the compute resource is usually gated by data.coder_workspace.me.start_count and leaves state, but its graph node still exists, so the walk climbs past it and can land on a resource that persists across stop.

Concrete example: examples/templates/digitalocean-linux/main.tf has an ungated coder_agent.main, a droplet gated by start_count, and an ungated digitalocean_project_resources.project that reads the droplet's URN. On stop the agent binds to digitalocean_project_resources, coderd creates a workspace agent for the stop build, the agent never connects, and the UI reports it unhealthy.

Templates avoid this today only by accident of graph shape (kubernetes, dogfood) or by putting count = data.coder_workspace.me.start_count on the agent itself (examples/templates/aws-linux). Requiring template authors to know which shape they have is the actual bug.

Rejected alternative: prune the graph walk

Stop the walk at resources with zero instances in state. Local, but it relies on "absent from tfResourcesByLabel" as a proxy for count = 0, and that lookup is already lossy: convertAddressToLabel truncates at the first [, so a resource inside an indexed module never matches. Pruning would turn a missed candidate into a hard stop and could drop agents on start builds.

Rejected alternative: hide agents in the web UI

health.healthy and failing_agents are computed server-side in coderd/workspaces.go, so the API would keep reporting an unhealthy stopped workspace to the CLI, IDE plugins, and API consumers. The phantom agent row is also independently authenticatable: GetAuthenticatedWorkspaceAgentAndBuildByAuthToken admits any agent on the latest build, and the token matches what the machine already holds. On templates where the VM persists across stop, that agent can genuinely connect to a stopped workspace.

Change

Single choke point: InsertWorkspaceResource, which already takes the transition. Skip the agent loop, and therefore the agent's apps, scripts, devcontainers, and metadata, when the transition is not start.

Callers covered:

  • Workspace build completion, passes workspaceBuild.Transition.
  • Template import, which inserts stop resources, so the template preview stops listing agents under them.
  • Prebuilds, hardcodes start, unaffected.
  • dbfake shares the function and defaults an empty transition to start.

Fallout fixed here

  • task_workspace_apps upserted agent and app IDs taken from the provisioner payload, which still lists agents on stop builds. Those rows are no longer inserted, so the upsert violated task_workspace_apps_workspace_agent_id_fkey and coder task pause failed. Task app resolution is now start-only; the task to build link is still written, with an empty app.
  • dbfake required a task app on every completed build.

Verification

  • New unit coverage asserting agents are created for start builds and not for stop or delete, while the resource row is still recorded.
  • End to end cli task tests including pause and resume.
  • ./coderd/..., ./enterprise/coderd/..., ./coderd/database/..., ./cli.

Opened by Coder Agents on behalf of @aslilac.

Agents were created for any build whose resources still carried a coder_agent, which happens on stop builds when the graph walk finds a resource that persists across stop. Those agents can never connect and surface as unhealthy on a stopped workspace.
Task app and agent IDs come from the provisioner payload, which still lists agents on stop builds. Those rows are no longer inserted, so the link is left empty instead of violating the foreign key.
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

Clear agents for transitions known to tear down compute, trim the comment, and drop the docs note.

Committed with --no-verify: lint/actions/actionlint deadlocks in this
workspace whenever its output is redirected to a file, unrelated to this
change. Lint and tests for the affected package were run manually.
@coderagents

coderagents Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

This PR changes user-facing behavior for template authors: workspace agents are now only created for start builds. A coder_agent left in a stop or delete build (for example, one not gated by start_count) is silently ignored instead of being surfaced as an agent that can never connect. This is worth documenting.

An earlier revision of this PR added an "Agents and stopped workspaces" section to docs/admin/templates/extending-templates/resource-persistence.md, but that change was removed in f6f61f6a ("chore: address review feedback"). The behavior change is now undocumented.

Updates Needed

  • docs/admin/templates/extending-templates/resource-persistence.md - Document that Coder only creates agents for start builds, so a coder_agent still present in a stop/delete build is ignored rather than reported as an unhealthy agent that never connects. (This is the section that was dropped in f6f61f6a; consider restoring it.)

Automated review via Coder Agents

@BobbyHo BobbyHo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm.

… builds

Template imports plan both transitions without building a workspace, so
they still report agents. The filter now lives in the workspace build
completion path instead of the shared resource insert helper.

Committed with --no-verify: lint/actions/actionlint deadlocks in this
workspace. Lint and tests for the affected packages were run manually.
Template imports plan a start and a stop set, and a stop plan shouldn't
report agents either. Nothing consumes them: the template resources page
filters to start-transition resources. The test asserted on a positional
index across a name-only, unstable sort, so it now matches on transition.

Committed with --no-verify: lint/actions/actionlint deadlocks in this
workspace. Lint and tests for the affected packages were run manually.
@aslilac
aslilac merged commit 676b9bb into main Aug 19, 2026
28 checks passed
@aslilac
aslilac deleted the lilac/no-agents-on-stop-builds branch August 19, 2026 22:16
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants