@Summary Watch all workspace builds @ID watch-all-workspace-builds @Security CoderSessionToken @Produce json @Tags Workspaces @Success 101 @Router /api/experimental/watch-all-workspacebuilds [get] @x-apidocgen {"skip": true}
(rw http.ResponseWriter, r *http.Request)
| 2252 | // @Router /api/experimental/watch-all-workspacebuilds [get] |
| 2253 | // @x-apidocgen {"skip": true} |
| 2254 | func (api *API) watchAllWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { |
| 2255 | ctx := r.Context() |
| 2256 | |
| 2257 | // Buffer enough updates to avoid blocking the pubsub callback while we're |
| 2258 | // accepting the WebSocket connection. Accepting the connection signals to |
| 2259 | // the client that the server is subscribed and ready to forward events. |
| 2260 | updates := make(chan codersdk.WorkspaceBuildUpdate, 256) |
| 2261 | |
| 2262 | cancelSubscribe, err := api.Pubsub.SubscribeWithErr(wspubsub.AllWorkspaceEventChannel, |
| 2263 | wspubsub.HandleWorkspaceBuildUpdate( |
| 2264 | func(_ context.Context, update codersdk.WorkspaceBuildUpdate, err error) { |
| 2265 | if err != nil { |
| 2266 | api.Logger.Warn(ctx, "workspace build update subscription error", slog.Error(err)) |
| 2267 | return |
| 2268 | } |
| 2269 | select { |
| 2270 | case updates <- update: |
| 2271 | default: |
| 2272 | api.Logger.Warn(ctx, "workspace build update dropped, client too slow") |
| 2273 | } |
| 2274 | })) |
| 2275 | if err != nil { |
| 2276 | httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ |
| 2277 | Message: "Internal error subscribing to workspace build events.", |
| 2278 | Detail: err.Error(), |
| 2279 | }) |
| 2280 | return |
| 2281 | } |
| 2282 | defer cancelSubscribe() |
| 2283 | |
| 2284 | conn, err := websocket.Accept(rw, r, nil) |
| 2285 | if err != nil { |
| 2286 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 2287 | Message: "Failed to accept WebSocket.", |
| 2288 | Detail: err.Error(), |
| 2289 | }) |
| 2290 | return |
| 2291 | } |
| 2292 | defer conn.Close(websocket.StatusNormalClosure, "done") |
| 2293 | |
| 2294 | // CloseRead starts a goroutine to read and discard messages from the client, |
| 2295 | // including Pong messages sent in response to our Ping heartbeats. |
| 2296 | _ = conn.CloseRead(context.Background()) |
| 2297 | |
| 2298 | ctx, cancel := context.WithCancel(ctx) |
| 2299 | go httpapi.HeartbeatClose(ctx, api.Logger, cancel, conn) |
| 2300 | defer cancel() |
| 2301 | |
| 2302 | enc := wsjson.NewEncoder[codersdk.WorkspaceBuildUpdate](conn, websocket.MessageText) |
| 2303 | for { |
| 2304 | select { |
| 2305 | case <-ctx.Done(): |
| 2306 | return |
| 2307 | case update, ok := <-updates: |
| 2308 | if !ok { |
| 2309 | return |
| 2310 | } |
| 2311 | if err := enc.Encode(update); err != nil { |
nothing calls this directly
no test coverage detected