Skip to content

Commit 202ffce

Browse files
authored
fix: remove deferred promise timeouts (#8835)
Issue #8832 makes a good point that we should not be making implicit assumptions about the client's performance when waiting for internal events. At the same time, we want to be able to get the debug info if some promises never resolve because of missing backend events. This PR adds a variable to turn on timeouts for deferred promises created using `createDebuggableDeferredPromise`. We can use it in our tests to catch never-resolving promises or when reproducing bug reports where Puppeteer hangs indefinitely. Closes #8832
1 parent 341b669 commit 202ffce

File tree

5 files changed

+37
-14
lines changed

5 files changed

+37
-14
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
"test": "c8 --check-coverage --lines 93 run-s test:chrome:* test:firefox",
3131
"test:types": "tsd",
3232
"test:install": "scripts/test-install.sh",
33-
"test:firefox": "cross-env PUPPETEER_PRODUCT=firefox MOZ_WEBRENDER=0 mocha",
33+
"test:firefox": "cross-env PUPPETEER_PRODUCT=firefox MOZ_WEBRENDER=0 PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
3434
"test:chrome": "run-s test:chrome:*",
35-
"test:chrome:headless": "cross-env HEADLESS=true mocha",
36-
"test:chrome:headless-chrome": "cross-env HEADLESS=chrome mocha",
37-
"test:chrome:headful": "cross-env HEADLESS=false mocha",
35+
"test:chrome:headless": "cross-env HEADLESS=true PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
36+
"test:chrome:headless-chrome": "cross-env HEADLESS=chrome PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
37+
"test:chrome:headful": "cross-env HEADLESS=false PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT=20000 mocha",
3838
"prepublishOnly": "npm run build",
3939
"prepare": "node typescript-if-required.js && husky install",
4040
"lint": "run-s lint:prettier lint:eslint",

src/common/FrameManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import {Protocol} from 'devtools-protocol';
1818
import {assert} from '../util/assert.js';
1919
import {
20-
createDeferredPromiseWithTimer,
20+
createDebuggableDeferredPromise,
2121
DeferredPromise,
2222
} from '../util/DeferredPromise.js';
2323
import {isErrorLike} from '../util/ErrorLike.js';
@@ -150,7 +150,7 @@ export class FrameManager extends EventEmitter {
150150
if (!this.#framesPendingTargetInit.has(targetId)) {
151151
this.#framesPendingTargetInit.set(
152152
targetId,
153-
createDeferredPromiseWithTimer(
153+
createDebuggableDeferredPromise(
154154
`Waiting for target frame ${targetId} failed`
155155
)
156156
);
@@ -318,7 +318,7 @@ export class FrameManager extends EventEmitter {
318318
if (!this.#framesPendingAttachment.has(frameId)) {
319319
this.#framesPendingAttachment.set(
320320
frameId,
321-
createDeferredPromiseWithTimer(
321+
createDebuggableDeferredPromise(
322322
`Waiting for frame ${frameId} to attach failed`
323323
)
324324
);

src/common/NetworkManager.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {HTTPResponse} from './HTTPResponse.js';
2424
import {FetchRequestId, NetworkEventManager} from './NetworkEventManager.js';
2525
import {debugError, isString} from './util.js';
2626
import {
27-
createDeferredPromiseWithTimer,
27+
createDebuggableDeferredPromise,
2828
DeferredPromise,
2929
} from '../util/DeferredPromise.js';
3030

@@ -144,9 +144,8 @@ export class NetworkManager extends EventEmitter {
144144
if (this.#deferredInitPromise) {
145145
return this.#deferredInitPromise;
146146
}
147-
this.#deferredInitPromise = createDeferredPromiseWithTimer<void>(
148-
'NetworkManager initialization timed out',
149-
30000
147+
this.#deferredInitPromise = createDebuggableDeferredPromise<void>(
148+
'NetworkManager initialization timed out'
150149
);
151150
const init = Promise.all([
152151
this.#ignoreHTTPSErrors

src/environment.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@
1818
* @internal
1919
*/
2020
export const isNode = !!(typeof process !== 'undefined' && process.version);
21+
22+
/**
23+
* @internal
24+
*/
25+
export const deferredPromiseDebugTimeout =
26+
typeof process !== 'undefined' &&
27+
typeof process.env['PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT'] !== 'undefined'
28+
? Number(process.env['PUPPETEER_DEFERRED_PROMISE_DEBUG_TIMEOUT'])
29+
: -1;

src/util/DeferredPromise.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import {TimeoutError} from '../common/Errors.js';
2+
import {deferredPromiseDebugTimeout} from '../environment.js';
23

34
/**
45
* @internal
56
*/
6-
77
export interface DeferredPromise<T> extends Promise<T> {
88
finished: () => boolean;
99
resolved: () => boolean;
1010
resolve: (_: T) => void;
1111
reject: (_: Error) => void;
1212
}
13+
1314
/**
1415
* Creates an returns a promise along with the resolve/reject functions.
1516
*
@@ -18,7 +19,6 @@ export interface DeferredPromise<T> extends Promise<T> {
1819
*
1920
* @internal
2021
*/
21-
2222
export function createDeferredPromiseWithTimer<T>(
2323
timeoutMessage: string,
2424
timeout = 5000
@@ -54,12 +54,12 @@ export function createDeferredPromiseWithTimer<T>(
5454
},
5555
});
5656
}
57+
5758
/**
5859
* Creates an returns a promise along with the resolve/reject functions.
5960
*
6061
* @internal
6162
*/
62-
6363
export function createDeferredPromise<T>(): DeferredPromise<T> {
6464
let isResolved = false;
6565
let isRejected = false;
@@ -86,3 +86,18 @@ export function createDeferredPromise<T>(): DeferredPromise<T> {
8686
},
8787
});
8888
}
89+
90+
/**
91+
* @internal
92+
*/
93+
export function createDebuggableDeferredPromise<T>(
94+
timeoutMessage: string
95+
): DeferredPromise<T> {
96+
if (deferredPromiseDebugTimeout > 0) {
97+
return createDeferredPromiseWithTimer(
98+
timeoutMessage,
99+
deferredPromiseDebugTimeout
100+
);
101+
}
102+
return createDeferredPromise();
103+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy