diff --git a/src/server/crPlaywright.ts b/src/server/crPlaywright.ts index 2a2d9c38d2..82774c5a38 100644 --- a/src/server/crPlaywright.ts +++ b/src/server/crPlaywright.ts @@ -67,7 +67,10 @@ export class CRBrowserServer { } async connect(): Promise { - return CRBrowser.connect(this._connectOptions); + const browser = await CRBrowser.connect(this._connectOptions); + // Hack: for typical launch scenario, ensure that close waits for actual process termination. + browser.close = this._gracefullyClose; + return browser; } process(): ChildProcess { diff --git a/src/server/ffPlaywright.ts b/src/server/ffPlaywright.ts index 583e59ee3d..62fd0560b4 100644 --- a/src/server/ffPlaywright.ts +++ b/src/server/ffPlaywright.ts @@ -64,7 +64,10 @@ export class FFBrowserServer { } async connect(): Promise { - return FFBrowser.connect(this._connectOptions); + const browser = await FFBrowser.connect(this._connectOptions); + // Hack: for typical launch scenario, ensure that close waits for actual process termination. + browser.close = this._gracefullyClose; + return browser; } process(): ChildProcess { diff --git a/src/server/processLauncher.ts b/src/server/processLauncher.ts index 2020981c7a..0d814ec810 100644 --- a/src/server/processLauncher.ts +++ b/src/server/processLauncher.ts @@ -23,6 +23,7 @@ import * as readline from 'readline'; import { TimeoutError } from '../errors'; import * as platform from '../platform'; +const debugLauncher = platform.debug('pw:launcher'); const removeFolderAsync = platform.promisify(removeFolder); export type LaunchProcessOptions = { @@ -43,7 +44,10 @@ export type LaunchProcessOptions = { type LaunchResult = { launchedProcess: childProcess.ChildProcess, gracefullyClose: () => Promise }; +let lastLaunchedId = 0; + export async function launchProcess(options: LaunchProcessOptions): Promise { + const id = ++lastLaunchedId; let stdio: ('ignore' | 'pipe')[] = ['pipe', 'pipe', 'pipe']; if (options.pipe) { if (options.dumpio) @@ -63,6 +67,7 @@ export async function launchProcess(options: LaunchProcessOptions): Promise ${options.executablePath} ${options.args.join(' ')}`); if (!spawnedProcess.pid) { let reject: (e: Error) => void; @@ -81,13 +86,14 @@ export async function launchProcess(options: LaunchProcessOptions): Promise { spawnedProcess.once('exit', () => { + debugLauncher(`[${id}] `); processClosed = true; helper.removeEventListeners(listeners); // Cleanup as processes exit. if (options.tempDir) { removeFolderAsync(options.tempDir) - .then(() => fulfill()) - .catch((err: Error) => console.error(err)); + .catch((err: Error) => console.error(err)) + .then(fulfill); } else { fulfill(); } @@ -111,14 +117,17 @@ export async function launchProcess(options: LaunchProcessOptions): Promise`); options.attemptToGracefullyClose().catch(() => killProcess()); // TODO: forcefully kill the process after some timeout. await waitForProcessToClose; + debugLauncher(`[${id}] `); helper.removeEventListeners(listeners); } // This method has to be sync to be used as 'exit' event handler. function killProcess() { + debugLauncher(`[${id}] `); helper.removeEventListeners(listeners); if (spawnedProcess.pid && !spawnedProcess.killed && !processClosed) { // Force kill chrome. diff --git a/src/server/wkPlaywright.ts b/src/server/wkPlaywright.ts index dfa64f03e8..757590b753 100644 --- a/src/server/wkPlaywright.ts +++ b/src/server/wkPlaywright.ts @@ -57,7 +57,10 @@ export class WKBrowserServer { } async connect(): Promise { - return WKBrowser.connect(this._connectOptions); + const browser = await WKBrowser.connect(this._connectOptions); + // Hack: for typical launch scenario, ensure that close waits for actual process termination. + browser.close = this._gracefullyClose; + return browser; } process(): ChildProcess {