Skip to content

chore(protocol): make timeout a protocol-level field#41712

Open
Skn0tt wants to merge 6 commits into
mainfrom
skn0tt-protocol-timeout-field
Open

chore(protocol): make timeout a protocol-level field#41712
Skn0tt wants to merge 6 commits into
mainfrom
skn0tt-protocol-timeout-field

Conversation

@Skn0tt

@Skn0tt Skn0tt commented Jul 9, 2026

Copy link
Copy Markdown
Member

Follows #41141, which made signal a protocol-level field. This does the same for timeout: every message carries it on Metadata, computed once on the client and read from progress.timeout on the server, instead of each method declaring its own timeout: float.

Metadata:
  timeout: float  # 👈 0 means "no timeout"

0 is the sentinel for "no deadline", matching what ProgressController.run already does. It's required on sendMessageToServer so the 0 is spelled out where it's genuinely meant, rather than hidden behind a ?? 0.

Most of the diff is mechanical - spec deletions plus regenerated channels/validator, staged separately for review.

Follows #41141, which made signal a protocol-level field. This does the
same for timeout: every message carries it on Metadata, computed once on
the client and read from progress.timeout on the server, instead of each
method declaring its own timeout: float. 0 is the sentinel for no deadline.
@Skn0tt Skn0tt requested a review from dgozman July 9, 2026 14:31
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ut-field

# Conflicts:
#	packages/playwright-core/src/client/channels.d.ts
#	packages/playwright-core/src/server/channels.d.ts
#	packages/protocol/src/validator.ts
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread utils/generate_channels.js Outdated
addScheme(`${derived}${titleCase(methodName)}ErrorDetails`, `tType('${errorDetailsName}')`);
}
channels_ts.push(` ${methodName}(params: ${paramsName}, ${isDispatcher ? `progress: Progress` : `signal: AbortSignal | undefined`}): Promise<${resultName}>;`);
channels_ts.push(` ${methodName}(params: ${paramsName}, ${isDispatcher ? `progress: Progress` : `options?: CommandOptions`}): Promise<${resultName}>;`);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are options now optional? Let's make them mandatory (like we had with the signal), so every caller thinks about it?


async uncheck(options: channels.ElementHandleUncheckOptions & TimeoutOptions = {}) {
return await this._elementChannel.uncheck({ ...options, timeout: this._frame._timeout(options) }, options.signal);
return await this._elementChannel.uncheck({ ...options }, { signal: options.signal, timeout: this._frame._timeout(options) });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make all the helper methods like this._frame._timeout(options) handle both timeout and signal - this way the code will be much easier everywhere.

Comment thread utils/generate_channels.js Outdated
export type { Binary, Channel, ${structNames.join(', ')} } from '@protocol/structs';
`];
` + (target === 'Dispatcher' ? '' : `
export type CommandOptions = { signal?: AbortSignal, timeout?: number };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make both properties required: { signal: AbortSignal | undefined, timeout: number } to ensure all callers doing the right thing?

Make signal and timeout required fields on the generated CommandOptions
struct, and pass them explicitly at every channel call site. Internal
calls that opt out of a deadline use timeout: 0 as the disabled sentinel.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@Skn0tt Skn0tt requested a review from dgozman July 13, 2026 12:21
this._timeoutSettings.setDefaultTimeout(timeout);
}

_timeout(options?: types.TimeoutOptions): channels.CommandOptions {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Call this _timeoutOptions() now?
  • Rename channels.CommandOptions to channels.TimeoutOptions?

if (this._connection.isRemote())
throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
return (await this._channel.pathAfterFinished({}, undefined)).value;
return (await this._channel.pathAfterFinished({}, { signal: undefined, timeout: 0 })).value;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about exporting a kNoTimeout constant from some common helper, e.g. TimeoutSettings.ts?

};
return await this._wrapApiCall(async () => {
const browser = Browser.from((await this._channel.launch(launchOptions, options.signal)).browser);
const browser = Browser.from((await this._channel.launch(launchOptions, { signal: options.signal, timeout: new TimeoutSettings().launchTimeout(options) })).browser);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TimeoutSettings.launchTimeout might as well handle the signal now.

noDefaults: params.noDefaults,
artifactsDir: params.artifactsDir,
}, undefined);
}, { signal: undefined, timeout: new TimeoutSettings().timeout(params) });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, let TimeoutSettings.timeout() handle the signal as well.

}

export async function connectToEndpoint(parentConnection: Connection, params: channels.LocalUtilsConnectParams): Promise<Connection> {
export async function connectToEndpoint(parentConnection: Connection, params: channels.LocalUtilsConnectParams, timeout: number): Promise<Connection> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accept TimeoutOptions instead of a number?

Skn0tt and others added 2 commits July 13, 2026 16:57
Addresses review feedback: rename CommandOptions to TimeoutOptions,
add a shared kNoTimeout sentinel, have TimeoutSettings resolvers return
the full { signal, timeout } options, and thread TimeoutOptions through
connectToEndpoint.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 110d728d-5d20-42f6-93b9-e80ab89b3f66
Inline options.signal in the resolvers and rename the loose input alias
to TimeoutInput to distinguish it from the resolved channels.TimeoutOptions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 110d728d-5d20-42f6-93b9-e80ab89b3f66
@github-actions

Copy link
Copy Markdown
Contributor

Test results for "MCP"

2 failed
❌ [chromium] › mcp/http.spec.ts:104 › http transport browser lifecycle (isolated) @mcp-ubuntu-latest-chromium
❌ [firefox] › mcp/http.spec.ts:104 › http transport browser lifecycle (isolated) @mcp-ubuntu-latest-firefox

7758 passed, 1249 skipped


Merge workflow run.

@github-actions

Copy link
Copy Markdown
Contributor

Test results for "tests 1"

3 flaky ⚠️ [chromium-library] › library/chromium/chromium.spec.ts:211 › should intercept service worker requests (main and within) `@chromium-ubuntu-22.04-node24`
⚠️ [chromium-library] › library/video.spec.ts:476 › screencast › should capture static page in persistent context @smoke `@chromium-ubuntu-22.04-node24`
⚠️ [chromium-library] › library/video.spec.ts:717 › screencast › should work with video+trace `@chromium-ubuntu-22.04-node22`

49546 passed, 1168 skipped


Merge workflow run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants