You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CoderWorkspacePoolMember: recognize a template-wide last_used_at write in a one-member pool #349
A CoderWorkspacePoolMember treats a later last_used_at as use, except for a template-wide write. It recognizes a template-wide write in two ways: the value is within 5 s of the template's updated_at, or another unclaimed member of the pool already moved its baseline to the same value.
When a template schedule update with update_workspace_last_used_at runs, and the template changes again before the next 60 s poll, and no other member of the pool saw the first write (for example a one-member pool), the member marks itself Used. The pool releases it, and one warm workspace leaks.
This is the fail-safe direction: the controller never deletes a workspace that someone may use. But it costs one workspace per affected member.
Possible fix
Also accept as a witness any other workspace of the template in Coder with the same last_used_at (one list call, only when the template time does not match).
Trigger
Before the PR 12 activation docs of #153, or a user report.
Found in review of #343 (thread 4268119093); the plan resolves the ambiguity toward Used, which can leak one warm workspace but never deletes possible work.
Two more cases from the final assessment of #343, where real use can be counted as "not used" (the side that leads toward replacement, not toward keep). Both windows are short: continued use bumps last_used_at again at the next usage flush, about 60 s later, so only a single short use can be missed.
5 s template guard false negative. The template's updated_at moves on every template edit (for example a version promote), not only on a schedule update with update_workspace_last_used_at. A use flush within ±5 s of an unrelated template edit is treated as a template-wide write and not counted as use.
Shared-flush sibling collision. Coder's usage tracker writes one shared now to every workspace in a flush batch (coderd/workspacestats/tracker.go, flush). The member compares whole seconds, so a sibling whose baseline came from the same flush or the same second makes this member's real use look like a template-wide write.
Also for the docs at activation: last_used_at is best-effort. Port-forward or raw tunnel connections with no session do not bump it under the usage experiment, and a failed flush drops updates.
Gate: decide and document before PR 12 registers the reconciler.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: medium
Activity
ThomasK33 commentedon Oct 14, 2026
Two more cases from the final assessment of #343, where real use can be counted as "not used" (the side that leads toward replacement, not toward keep). Both windows are short: continued use bumps
last_used_atagain at the next usage flush, about 60 s later, so only a single short use can be missed.updated_atmoves on every template edit (for example a version promote), not only on a schedule update withupdate_workspace_last_used_at. A use flush within ±5 s of an unrelated template edit is treated as a template-wide write and not counted as use.nowto every workspace in a flush batch (coderd/workspacestats/tracker.go,flush). The member compares whole seconds, so a sibling whose baseline came from the same flush or the same second makes this member's real use look like a template-wide write.Also for the docs at activation:
last_used_atis best-effort. Port-forward or raw tunnel connections with no session do not bump it under the usage experiment, and a failed flush drops updates.Gate: decide and document before PR 12 registers the reconciler.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:medium