* Check if runtime is ready for use. * * Behavior: * - If creation failed during postCreateSetup(), fail fast. * - If workspace is running: return ready. * - If workspace is stopped: auto-start and wait (blocking, ~120s timeout). * - If workspace is stopping: poll until stopped, th
(options?: EnsureReadyOptions)
| 218 | * Concurrency: shares an in-flight promise to avoid duplicate start sequences. |
| 219 | */ |
| 220 | override async ensureReady(options?: EnsureReadyOptions): Promise<EnsureReadyResult> { |
| 221 | const workspaceName = this.coderConfig.workspaceName; |
| 222 | if (!workspaceName) { |
| 223 | return { |
| 224 | ready: false, |
| 225 | error: "Coder workspace name not set", |
| 226 | errorType: "runtime_not_ready", |
| 227 | }; |
| 228 | } |
| 229 | |
| 230 | const now = Date.now(); |
| 231 | const activityByWorkspace = getCoderActivityMap(this.coderService); |
| 232 | pruneCoderActivityMap(activityByWorkspace, now); |
| 233 | const lastActivityAtMs = activityByWorkspace.get(workspaceName) ?? 0; |
| 234 | |
| 235 | // Fast path: recently active, skip expensive status check. This cache intentionally lives |
| 236 | // outside the runtime instance because existing-workspace stream startup recreates runtimes, |
| 237 | // and it prunes entries after the same 5-minute window to avoid unbounded workspace-name growth. |
| 238 | if (lastActivityAtMs !== 0 && now - lastActivityAtMs < CODER_INACTIVITY_THRESHOLD_MS) { |
| 239 | return { ready: true }; |
| 240 | } |
| 241 | |
| 242 | // Avoid duplicate start/wait sequences only for calls without request-local observers. |
| 243 | // Abort signals and status sinks are per caller; sharing those would make cancellation/status |
| 244 | // delivery depend on whichever caller happened to start the singleflight. |
| 245 | if (options?.signal || options?.statusSink) { |
| 246 | return this.doEnsureReady(workspaceName, options); |
| 247 | } |
| 248 | if (this.ensureReadyPromise) { |
| 249 | return this.ensureReadyPromise; |
| 250 | } |
| 251 | |
| 252 | this.ensureReadyPromise = this.doEnsureReady(workspaceName, options); |
| 253 | try { |
| 254 | return await this.ensureReadyPromise; |
| 255 | } finally { |
| 256 | this.ensureReadyPromise = null; |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Core ensureReady logic - called once (protected by ensureReadyPromise). |
nothing calls this directly
no test coverage detected