| 209 | } |
| 210 | |
| 211 | private onMessage(w: ParsePoolWorker, m: ParseWorkerMessage): void { |
| 212 | if (m.type === 'grammars-loaded') { |
| 213 | if (!this.workers.has(w)) return; // recycled/destroyed before ready |
| 214 | this.pending.delete(w); |
| 215 | this.idle.push(w); |
| 216 | this.drain(); |
| 217 | return; |
| 218 | } |
| 219 | if (m.type === 'parse-result') { |
| 220 | const job = this.inflight.get(w); |
| 221 | if (!job || (m.id !== undefined && m.id !== job.id)) return; // stale (post-recycle) |
| 222 | this.inflight.delete(w); |
| 223 | // Recycle the worker once it's done enough parses to have grown its WASM |
| 224 | // heap; otherwise return it to the idle set for the next job. |
| 225 | if ((this.parseCounts.get(w) ?? 0) >= this.recycleInterval) { |
| 226 | this.recycle(w); |
| 227 | } else { |
| 228 | this.idle.push(w); |
| 229 | } |
| 230 | this.settle(job, m.result); |
| 231 | this.drain(); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | /** A worker died (crash hook / OOM exit / spawn error). Reject its in-flight |
| 236 | * parse so the caller's retry pass can re-attempt it, then respawn. */ |