feat: add coderd_api_websocket_probes_total metric (#25012)

Relates to CODAGT-115

Adds metric `coderd_api_websocket_probes_total`. Every successful
heartbeat for a given path will increment the metric.

Comparing this with `coderd_api_concurrent_websockets` will give an
indication of how many websocket connections are open but in a 'wedged'
state (when heartbeats stopped versus when we closed the connection).
This commit is contained in:
Cian Johnston
2026-06-03 10:46:07 +01:00
committed by GitHub
parent 7703e7a26e
commit 8b058dc949
22 changed files with 596 additions and 171 deletions
+6 -8
View File
@@ -501,7 +501,7 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) {
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go httpapi.HeartbeatClose(ctx, api.Logger, cancel, conn)
ctx = api.wsWatcher.Watch(ctx, api.Logger, conn)
encoder := wsjson.NewEncoder[[]codersdk.WorkspaceAgentLog](conn, websocket.MessageText)
defer encoder.Close(websocket.StatusNormalClosure)
@@ -861,7 +861,7 @@ func (api *API) watchWorkspaceAgentContainers(rw http.ResponseWriter, r *http.Re
return
}
ctx, cancel := context.WithCancel(r.Context())
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Here we close the websocket for reading, so that the websocket library will handle pings and
@@ -871,7 +871,7 @@ func (api *API) watchWorkspaceAgentContainers(rw http.ResponseWriter, r *http.Re
ctx, wsNetConn := codersdk.WebsocketNetConn(ctx, conn, websocket.MessageText)
defer wsNetConn.Close()
go httpapi.HeartbeatCloseWithClock(ctx, logger, cancel, conn, api.Clock)
ctx = api.wsWatcher.Watch(ctx, logger, conn)
encoder := json.NewEncoder(wsNetConn)
@@ -1371,9 +1371,7 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
ctx, wsNetConn := codersdk.WebsocketNetConn(ctx, conn, websocket.MessageBinary)
defer wsNetConn.Close()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go httpapi.HeartbeatClose(ctx, api.Logger, cancel, conn)
ctx = api.wsWatcher.Watch(ctx, api.Logger, conn)
defer conn.Close(websocket.StatusNormalClosure, "")
err = api.TailnetClientService.ServeClient(ctx, version, wsNetConn, tailnet.StreamID{
@@ -1670,7 +1668,7 @@ func (api *API) watchWorkspaceAgentMetadataSSE(rw http.ResponseWriter, r *http.R
// @Router /api/v2/workspaceagents/{workspaceagent}/watch-metadata-ws [get]
// @x-apidocgen {"skip": true}
func (api *API) watchWorkspaceAgentMetadataWS(rw http.ResponseWriter, r *http.Request) {
api.watchWorkspaceAgentMetadata(rw, r, httpapi.OneWayWebSocketEventSender(api.Logger))
api.watchWorkspaceAgentMetadata(rw, r, httpapi.OneWayWebSocketEventSender(api.Logger, api.wsWatcher))
}
func (api *API) watchWorkspaceAgentMetadata(
@@ -2301,7 +2299,7 @@ func (api *API) tailnetRPCConn(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go httpapi.HeartbeatClose(ctx, api.Logger, cancel, conn)
ctx = api.wsWatcher.Watch(ctx, api.Logger, conn)
err = api.TailnetClientService.ServeClient(ctx, version, wsNetConn, tailnet.StreamID{
Name: "client",
ID: peerID,