Close waits for all WebSocket connections to drain before returning.
()
| 2279 | |
| 2280 | // Close waits for all WebSocket connections to drain before returning. |
| 2281 | func (api *API) Close() error { |
| 2282 | select { |
| 2283 | case <-api.ctx.Done(): |
| 2284 | return xerrors.New("API already closed") |
| 2285 | default: |
| 2286 | api.cancel() |
| 2287 | } |
| 2288 | |
| 2289 | wsDone := make(chan struct{}) |
| 2290 | timer := time.NewTimer(10 * time.Second) |
| 2291 | defer timer.Stop() |
| 2292 | go func() { |
| 2293 | api.WebsocketWaitMutex.Lock() |
| 2294 | defer api.WebsocketWaitMutex.Unlock() |
| 2295 | api.WebsocketWaitGroup.Wait() |
| 2296 | close(wsDone) |
| 2297 | }() |
| 2298 | // This will technically leak the above func if the timer fires, but this is |
| 2299 | // maintly a last ditch effort to un-stuck coderd on shutdown. This |
| 2300 | // shouldn't affect tests at all. |
| 2301 | select { |
| 2302 | case <-wsDone: |
| 2303 | case <-timer.C: |
| 2304 | api.Logger.Warn(api.ctx, "websocket shutdown timed out after 10 seconds") |
| 2305 | } |
| 2306 | api.dbRolluper.Close() |
| 2307 | // chatDiffWorker is unconditionally initialized in New(). |
| 2308 | select { |
| 2309 | case <-api.gitSyncWorker.Done(): |
| 2310 | case <-time.After(10 * time.Second): |
| 2311 | api.Logger.Warn(context.Background(), |
| 2312 | "chat diff refresh worker did not exit in time") |
| 2313 | } |
| 2314 | if err := api.chatDaemon.Close(); err != nil { |
| 2315 | api.Logger.Warn(api.ctx, "close chat processor", slog.Error(err)) |
| 2316 | } |
| 2317 | api.metricsCache.Close() |
| 2318 | if api.updateChecker != nil { |
| 2319 | api.updateChecker.Close() |
| 2320 | } |
| 2321 | _ = api.workspaceAppServer.Close() |
| 2322 | _ = api.agentProvider.Close() |
| 2323 | if api.derpCloseFunc != nil { |
| 2324 | api.derpCloseFunc() |
| 2325 | } |
| 2326 | // The coordinator should be closed after the agent provider, and the DERP |
| 2327 | // handler. |
| 2328 | coordinator := api.TailnetCoordinator.Load() |
| 2329 | if coordinator != nil { |
| 2330 | _ = (*coordinator).Close() |
| 2331 | } |
| 2332 | _ = api.statsReporter.Close() |
| 2333 | if api.metadataBatcher != nil { |
| 2334 | api.metadataBatcher.Close() |
| 2335 | } |
| 2336 | _ = api.NetworkTelemetryBatcher.Close() |
| 2337 | _ = api.OIDCConvertKeyCache.Close() |
| 2338 | _ = api.AppSigningKeyCache.Close() |