| 282 | } |
| 283 | |
| 284 | private onTimeout(w: ParsePoolWorker, job: ParseJob, ms: number): void { |
| 285 | if (job.settled || !this.workers.has(w)) return; |
| 286 | this.log(`TIMEOUT: ${job.task.filePath} exceeded ${ms}ms — killing worker`); |
| 287 | // Kill the (possibly WASM-wedged) worker and reject this parse. A timeout |
| 288 | // isn't a crash — don't charge the budget — but the worker is gone, so spawn |
| 289 | // a replacement to keep capacity. |
| 290 | this.removeWorker(w); |
| 291 | this.inflight.delete(w); |
| 292 | try { void w.terminate(); } catch { /* already gone */ } |
| 293 | this.settle(job, undefined, new Error(`Parse timed out after ${ms}ms`)); |
| 294 | if (this.healthy) this.spawnOne(); |
| 295 | this.drain(); |
| 296 | } |
| 297 | |
| 298 | private drain(): void { |
| 299 | // Grow toward maxSize while queued work outstrips workers that are idle OR |