| 147 | } |
| 148 | |
| 149 | private constructor(workerScript: string, dbPath: string, projectRoot: string, size: number) { |
| 150 | for (let i = 0; i < size; i++) { |
| 151 | const worker = new Worker(workerScript); |
| 152 | let readyResolve!: () => void; |
| 153 | let readyReject!: (e: Error) => void; |
| 154 | const ready = new Promise<void>((resolve, reject) => { |
| 155 | readyResolve = resolve; |
| 156 | readyReject = reject; |
| 157 | }); |
| 158 | const pw: PoolWorker = { worker, ready, busy: 0 }; |
| 159 | worker.on('message', (msg: { type: string; id?: number; message?: string; edges?: Edge[]; ms?: number } & Partial<ChunkResult>) => { |
| 160 | if (msg.type === 'ready') { |
| 161 | readyResolve(); |
| 162 | } else if (msg.type === 'result' && msg.id !== undefined) { |
| 163 | pw.busy--; |
| 164 | const waiter = this.waiters.get(msg.id); |
| 165 | this.waiters.delete(msg.id); |
| 166 | waiter?.resolve({ |
| 167 | resolved: msg.resolved!, |
| 168 | unresolved: msg.unresolved!, |
| 169 | deferredChain: msg.deferredChain!, |
| 170 | deferredThisMember: msg.deferredThisMember!, |
| 171 | byMethod: msg.byMethod!, |
| 172 | }); |
| 173 | } else if (msg.type === 'synth-result' && msg.id !== undefined) { |
| 174 | pw.busy--; |
| 175 | const waiter = this.synthWaiters.get(msg.id); |
| 176 | this.synthWaiters.delete(msg.id); |
| 177 | waiter?.resolve({ edges: msg.edges ?? [], ms: msg.ms ?? 0 }); |
| 178 | } else if (msg.type === 'recycled' && msg.id !== undefined) { |
| 179 | const waiter = this.recycleWaiters.get(msg.id); |
| 180 | this.recycleWaiters.delete(msg.id); |
| 181 | waiter?.(); |
| 182 | } else if (msg.type === 'error') { |
| 183 | pw.busy--; |
| 184 | const err = new Error(`resolver worker: ${msg.message}`); |
| 185 | if (msg.id !== undefined && this.waiters.has(msg.id)) { |
| 186 | const waiter = this.waiters.get(msg.id)!; |
| 187 | this.waiters.delete(msg.id); |
| 188 | waiter.reject(err); |
| 189 | } else if (msg.id !== undefined && this.synthWaiters.has(msg.id)) { |
| 190 | const waiter = this.synthWaiters.get(msg.id)!; |
| 191 | this.synthWaiters.delete(msg.id); |
| 192 | waiter.reject(err); |
| 193 | } else { |
| 194 | this.fail(err); |
| 195 | } |
| 196 | } |
| 197 | }); |
| 198 | worker.on('error', (err) => { |
| 199 | this.fail(err instanceof Error ? err : new Error(String(err))); |
| 200 | readyReject(this.failed!); |
| 201 | }); |
| 202 | worker.on('exit', (code) => { |
| 203 | if (code !== 0) { |
| 204 | this.fail(new Error(`resolver worker exited with code ${code}`)); |
| 205 | readyReject(this.failed!); |
| 206 | } |