@@ -354,6 +354,28 @@ function hasChildExited(child: ChildProcess) {
|
354 | 354 | return child.exitCode !== null || child.signalCode !== null; |
355 | 355 | } |
356 | 356 | |
| 357 | +function isProcessAlreadyExitedError(error: unknown): boolean { |
| 358 | +return (error as NodeJS.ErrnoException | undefined)?.code === "ESRCH"; |
| 359 | +} |
| 360 | + |
| 361 | +function isQaGatewayChildProcessTreeAlive(child: ChildProcess) { |
| 362 | +if (!child.pid) { |
| 363 | +return false; |
| 364 | +} |
| 365 | +if (process.platform === "win32") { |
| 366 | +return !hasChildExited(child); |
| 367 | +} |
| 368 | +try { |
| 369 | +process.kill(-child.pid, 0); |
| 370 | +return true; |
| 371 | +} catch (error) { |
| 372 | +if (isProcessAlreadyExitedError(error)) { |
| 373 | +return false; |
| 374 | +} |
| 375 | +return !hasChildExited(child); |
| 376 | +} |
| 377 | +} |
| 378 | + |
357 | 379 | function signalQaGatewayChildProcessTree(child: ChildProcess, signal: NodeJS.Signals) { |
358 | 380 | if (!child.pid) { |
359 | 381 | return; |
@@ -374,22 +396,21 @@ function signalQaGatewayChildProcessTree(child: ChildProcess, signal: NodeJS.Sig
|
374 | 396 | } |
375 | 397 | |
376 | 398 | async function waitForQaGatewayChildExit(child: ChildProcess, timeoutMs: number) { |
377 | | -if (hasChildExited(child)) { |
378 | | -return true; |
| 399 | +const deadline = Date.now() + timeoutMs; |
| 400 | +while (Date.now() <= deadline) { |
| 401 | +if (!isQaGatewayChildProcessTreeAlive(child)) { |
| 402 | +return true; |
| 403 | +} |
| 404 | +await sleep(Math.min(25, Math.max(0, deadline - Date.now()))); |
379 | 405 | } |
380 | | -return await Promise.race([ |
381 | | -new Promise<boolean>((resolve) => { |
382 | | -child.once("exit", () => resolve(true)); |
383 | | -}), |
384 | | -sleep(timeoutMs).then(() => false), |
385 | | -]); |
| 406 | +return !isQaGatewayChildProcessTreeAlive(child); |
386 | 407 | } |
387 | 408 | |
388 | 409 | async function stopQaGatewayChildProcessTree( |
389 | 410 | child: ChildProcess, |
390 | 411 | opts?: { gracefulTimeoutMs?: number; forceTimeoutMs?: number }, |
391 | 412 | ) { |
392 | | -if (hasChildExited(child)) { |
| 413 | +if (!isQaGatewayChildProcessTreeAlive(child)) { |
393 | 414 | return; |
394 | 415 | } |
395 | 416 | signalQaGatewayChildProcessTree(child, "SIGTERM"); |
|