chore: add agent-connection-watch for workspaces (#24507)

<!--

If you have used AI to produce some or all of this PR, please ensure you have read our [AI Contribution guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING) before submitting.

-->

relates to GRU-18  
  
Adds basic implementation for Workspace Agent Connection Watch and tests.  
  
Missing are handling of logs.
This commit is contained in:
Spike Curtis
2026-05-20 13:09:11 -04:00
committed by GitHub
parent 05e47b9c0f
commit 8dc4d76890
20 changed files with 1679 additions and 61 deletions
+7
View File
@@ -92,6 +92,7 @@ import (
"github.com/coder/coder/v2/coderd/webpush"
"github.com/coder/coder/v2/coderd/workspaceapps"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
"github.com/coder/coder/v2/coderd/workspaceconnwatcher"
"github.com/coder/coder/v2/coderd/workspacestats"
"github.com/coder/coder/v2/coderd/wsbuilder"
"github.com/coder/coder/v2/coderd/x/chatd"
@@ -923,6 +924,8 @@ func New(options *Options) *API {
APIKeyEncryptionKeycache: options.AppEncryptionKeyCache,
})
api.workspaceAgentConnWatcher = workspaceconnwatcher.New(api.ctx, options.Logger, options.Pubsub, options.Database)
apiKeyMiddleware := httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{
DB: options.Database,
ActivateDormantUser: ActivateDormantUser(options.Logger, &api.Auditor, options.Database),
@@ -1820,6 +1823,7 @@ func New(options *Options) *API {
r.Patch("/", api.patchWorkspaceACL)
r.Delete("/", api.deleteWorkspaceACL)
})
r.Get("/agent-connection-watch", api.workspaceAgentConnWatcher.WorkspaceAgentConnectionWatch)
})
})
r.Route("/workspacebuilds/{workspacebuild}", func(r chi.Router) {
@@ -2238,6 +2242,8 @@ type API struct {
// profile collection (via /debug/profile) can run at a time. The CPU
// profiler is process-global, so concurrent collections would fail.
ProfileCollecting atomic.Bool
workspaceAgentConnWatcher *workspaceconnwatcher.Watcher
}
// Close waits for all WebSocket connections to drain before returning.
@@ -2301,6 +2307,7 @@ func (api *API) Close() error {
_ = api.AppSigningKeyCache.Close()
_ = api.AppEncryptionKeyCache.Close()
_ = api.UpdatesProvider.Close()
api.workspaceAgentConnWatcher.Close()
if current := api.PrebuildsReconciler.Load(); current != nil {
ctx, giveUp := context.WithTimeoutCause(context.Background(), time.Second*30, xerrors.New("gave up waiting for reconciler to stop before shutdown"))