Skip to content

Commit 63d898d

Browse files
authored
chore: replace some progress.cleanup calls with try/catch (microsoft#36769)
1 parent f3666e1 commit 63d898d

File tree

16 files changed

+305
-225
lines changed

16 files changed

+305
-225
lines changed

packages/playwright-core/src/server/android/android.ts

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { removeFolders } from '../utils/fileUtils';
3434
import { helper } from '../helper';
3535
import { SdkObject, serverSideCallMetadata } from '../instrumentation';
3636
import { gracefullyCloseSet } from '../utils/processLauncher';
37-
import { isAbortError, Progress, ProgressController } from '../progress';
37+
import { isAbortError, Progress, ProgressController, raceUncancellableOperationWithCleanup } from '../progress';
3838
import { registry } from '../registry';
3939

4040
import type { BrowserOptions, BrowserProcess } from '../browser';
@@ -79,8 +79,7 @@ export class Android extends SdkObject {
7979
newSerials.add(d.serial);
8080
if (this._devices.has(d.serial))
8181
continue;
82-
const device = await progress.raceWithCleanup(AndroidDevice.create(this, d, options), device => device.close());
83-
this._devices.set(d.serial, device);
82+
await progress.race(AndroidDevice.create(this, d, options).then(device => this._devices.set(d.serial, device)));
8483
}
8584
for (const d of this._devices.keys()) {
8685
if (!newSerials.has(d))
@@ -152,7 +151,7 @@ export class AndroidDevice extends SdkObject {
152151
}
153152

154153
async open(progress: Progress, command: string): Promise<SocketBackend> {
155-
return await progress.raceWithCleanup(this._backend.open(`${command}`), socket => socket.close());
154+
return await this._open(progress, command);
156155
}
157156

158157
async screenshot(): Promise<Buffer> {
@@ -216,7 +215,7 @@ export class AndroidDevice extends SdkObject {
216215
debug('pw:android')(`Polling the socket localabstract:${socketName}`);
217216
while (!socket) {
218217
try {
219-
socket = await progress.raceWithCleanup(this._backend.open(`localabstract:${socketName}`), socket => socket.close());
218+
socket = await this._open(progress, `localabstract:${socketName}`);
220219
} catch (e) {
221220
if (isAbortError(e))
222221
throw e;
@@ -273,8 +272,13 @@ export class AndroidDevice extends SdkObject {
273272
await progress.race(this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString('base64')}" | base64 -d > /data/local/tmp/chrome-command-line`));
274273
await progress.race(this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`));
275274
const browserContext = await this._connectToBrowser(progress, socketName, options);
276-
await progress.race(this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`));
277-
return browserContext;
275+
try {
276+
await progress.race(this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`));
277+
return browserContext;
278+
} catch (error) {
279+
await browserContext.close({ reason: 'Failed to launch' }).catch(() => {});
280+
throw error;
281+
}
278282
}
279283

280284
private _defaultArgs(options: channels.AndroidDeviceLaunchBrowserParams, socketName: string): string[] {
@@ -315,43 +319,50 @@ export class AndroidDevice extends SdkObject {
315319

316320
private async _connectToBrowser(progress: Progress, socketName: string, options: types.BrowserContextOptions = {}): Promise<BrowserContext> {
317321
const socket = await this._waitForLocalAbstract(progress, socketName);
318-
const androidBrowser = new AndroidBrowser(this, socket);
319-
progress.cleanupWhenAborted(() => androidBrowser.close());
320-
await progress.race(androidBrowser._init());
321-
this._browserConnections.add(androidBrowser);
322-
323-
const artifactsDir = await progress.race(fs.promises.mkdtemp(ARTIFACTS_FOLDER));
324-
const cleanupArtifactsDir = async () => {
325-
const errors = (await removeFolders([artifactsDir])).filter(Boolean);
326-
for (let i = 0; i < (errors || []).length; ++i)
327-
debug('pw:android')(`exception while removing ${artifactsDir}: ${errors[i]}`);
328-
};
329-
progress.cleanupWhenAborted(cleanupArtifactsDir);
330-
gracefullyCloseSet.add(cleanupArtifactsDir);
331-
socket.on('close', async () => {
332-
gracefullyCloseSet.delete(cleanupArtifactsDir);
333-
cleanupArtifactsDir().catch(e => debug('pw:android')(`could not cleanup artifacts dir: ${e}`));
334-
});
335-
const browserOptions: BrowserOptions = {
336-
name: 'clank',
337-
isChromium: true,
338-
slowMo: 0,
339-
persistent: { ...options, noDefaultViewport: true },
340-
artifactsDir,
341-
downloadsPath: artifactsDir,
342-
tracesDir: artifactsDir,
343-
browserProcess: new ClankBrowserProcess(androidBrowser),
344-
proxy: options.proxy,
345-
protocolLogger: helper.debugProtocolLogger(),
346-
browserLogsCollector: new RecentLogsCollector(),
347-
originalLaunchOptions: {},
348-
};
349-
validateBrowserContextOptions(options, browserOptions);
322+
try {
323+
const androidBrowser = new AndroidBrowser(this, socket);
324+
await progress.race(androidBrowser._init());
325+
this._browserConnections.add(androidBrowser);
326+
327+
const artifactsDir = await progress.race(fs.promises.mkdtemp(ARTIFACTS_FOLDER));
328+
const cleanupArtifactsDir = async () => {
329+
const errors = (await removeFolders([artifactsDir])).filter(Boolean);
330+
for (let i = 0; i < (errors || []).length; ++i)
331+
debug('pw:android')(`exception while removing ${artifactsDir}: ${errors[i]}`);
332+
};
333+
gracefullyCloseSet.add(cleanupArtifactsDir);
334+
socket.on('close', async () => {
335+
gracefullyCloseSet.delete(cleanupArtifactsDir);
336+
cleanupArtifactsDir().catch(e => debug('pw:android')(`could not cleanup artifacts dir: ${e}`));
337+
});
338+
const browserOptions: BrowserOptions = {
339+
name: 'clank',
340+
isChromium: true,
341+
slowMo: 0,
342+
persistent: { ...options, noDefaultViewport: true },
343+
artifactsDir,
344+
downloadsPath: artifactsDir,
345+
tracesDir: artifactsDir,
346+
browserProcess: new ClankBrowserProcess(androidBrowser),
347+
proxy: options.proxy,
348+
protocolLogger: helper.debugProtocolLogger(),
349+
browserLogsCollector: new RecentLogsCollector(),
350+
originalLaunchOptions: {},
351+
};
352+
validateBrowserContextOptions(options, browserOptions);
353+
354+
const browser = await progress.race(CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions));
355+
const defaultContext = browser._defaultContext!;
356+
await defaultContext._loadDefaultContextAsIs(progress);
357+
return defaultContext;
358+
} catch (error) {
359+
socket.close();
360+
throw error;
361+
}
362+
}
350363

351-
const browser = await progress.race(CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions));
352-
const defaultContext = browser._defaultContext!;
353-
await defaultContext._loadDefaultContextAsIs(progress);
354-
return defaultContext;
364+
private _open(progress: Progress, command: string): Promise<SocketBackend> {
365+
return raceUncancellableOperationWithCleanup(progress, () => this._backend.open(command), socket => socket.close());
355366
}
356367

357368
webViews(): channels.AndroidWebView[] {
@@ -361,7 +372,7 @@ export class AndroidDevice extends SdkObject {
361372
async installApk(progress: Progress, content: Buffer, options?: { args?: string[] }): Promise<void> {
362373
const args = options && options.args ? options.args : ['-r', '-t', '-S'];
363374
debug('pw:android')('Opening install socket');
364-
const installSocket = await progress.raceWithCleanup(this._backend.open(`shell:cmd package install ${args.join(' ')} ${content.length}`), socket => socket.close());
375+
const installSocket = await this._open(progress, `shell:cmd package install ${args.join(' ')} ${content.length}`);
365376
debug('pw:android')('Writing driver bytes: ' + content.length);
366377
await progress.race(installSocket.write(content));
367378
const success = await progress.race(new Promise(f => installSocket.on('data', f)));
@@ -370,7 +381,7 @@ export class AndroidDevice extends SdkObject {
370381
}
371382

372383
async push(progress: Progress, content: Buffer, path: string, mode = 0o644): Promise<void> {
373-
const socket = await progress.raceWithCleanup(this._backend.open(`sync:`), socket => socket.close());
384+
const socket = await this._open(progress, `sync:`);
374385
const sendHeader = async (command: string, length: number) => {
375386
const buffer = Buffer.alloc(command.length + 4);
376387
buffer.write(command, 0);

packages/playwright-core/src/server/bidi/bidiChromium.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class BidiChromium extends BrowserType {
8282
}
8383

8484
override attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void {
85+
// Note that it's fine to reuse the transport, since our connection ignores kBrowserCloseMessageId.
8586
const bidiTransport = (transport as any)[kBidiOverCdpWrapper];
8687
if (bidiTransport)
8788
transport = bidiTransport;

packages/playwright-core/src/server/bidi/bidiFirefox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export class BidiFirefox extends BrowserType {
7878
}
7979

8080
override attemptToGracefullyCloseBrowser(transport: ConnectionTransport): void {
81+
// Note that it's fine to reuse the transport, since our connection ignores kBrowserCloseMessageId.
8182
transport.send({ method: 'browser.close', params: {}, id: kBrowserCloseMessageId });
8283
}
8384

packages/playwright-core/src/server/browser.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ import { Download } from './download';
2020
import { SdkObject } from './instrumentation';
2121
import { Page } from './page';
2222
import { ClientCertificatesProxy } from './socksClientCertificatesInterceptor';
23-
import { ProgressController } from './progress';
2423

25-
import type { CallMetadata } from './instrumentation';
2624
import type * as types from './types';
2725
import type { ProxySettings } from './types';
2826
import type { RecentLogsCollector } from './utils/debugLogger';
@@ -92,28 +90,30 @@ export abstract class Browser extends SdkObject {
9290
return this.options.sdkLanguage || this.attribution.playwright.options.sdkLanguage;
9391
}
9492

95-
newContextFromMetadata(metadata: CallMetadata, options: types.BrowserContextOptions): Promise<BrowserContext> {
96-
const controller = new ProgressController(metadata, this);
97-
return controller.run(progress => this.newContext(progress, options));
98-
}
99-
10093
async newContext(progress: Progress, options: types.BrowserContextOptions): Promise<BrowserContext> {
10194
validateBrowserContextOptions(options, this.options);
10295
let clientCertificatesProxy: ClientCertificatesProxy | undefined;
103-
if (options.clientCertificates?.length) {
104-
clientCertificatesProxy = await progress.raceWithCleanup(ClientCertificatesProxy.create(options), proxy => proxy.close());
105-
options = { ...options };
106-
options.proxyOverride = clientCertificatesProxy.proxySettings();
107-
options.internalIgnoreHTTPSErrors = true;
96+
let context: BrowserContext | undefined;
97+
try {
98+
if (options.clientCertificates?.length) {
99+
clientCertificatesProxy = await ClientCertificatesProxy.create(progress, options);
100+
options = { ...options };
101+
options.proxyOverride = clientCertificatesProxy.proxySettings();
102+
options.internalIgnoreHTTPSErrors = true;
103+
}
104+
context = await progress.race(this.doCreateNewContext(options));
105+
context._clientCertificatesProxy = clientCertificatesProxy;
106+
if ((options as any).__testHookBeforeSetStorageState)
107+
await progress.race((options as any).__testHookBeforeSetStorageState());
108+
if (options.storageState)
109+
await context.setStorageState(progress, options.storageState);
110+
this.emit(Browser.Events.Context, context);
111+
return context;
112+
} catch (error) {
113+
await context?.close({ reason: 'Failed to create context' }).catch(() => {});
114+
await clientCertificatesProxy?.close().catch(() => {});
115+
throw error;
108116
}
109-
const context = await progress.raceWithCleanup(this.doCreateNewContext(options), context => context.close({ reason: 'Failed to create context' }));
110-
context._clientCertificatesProxy = clientCertificatesProxy;
111-
if ((options as any).__testHookBeforeSetStorageState)
112-
await progress.race((options as any).__testHookBeforeSetStorageState());
113-
if (options.storageState)
114-
await context.setStorageState(progress, options.storageState);
115-
this.emit(Browser.Events.Context, context);
116-
return context;
117117
}
118118

119119
async newContextForReuse(progress: Progress, params: channels.BrowserNewContextForReuseParams): Promise<BrowserContext> {

0 commit comments

Comments
 (0)