Skip to content

Add pagination of batch requests - #64061

Open
Wesley Wigham (weswigham) wants to merge 2 commits into
microsoft:mainfrom
weswigham:api-batch-pagination
Open

Add pagination of batch requests#64061
Wesley Wigham (weswigham) wants to merge 2 commits into
microsoft:mainfrom
weswigham:api-batch-pagination

Conversation

@weswigham

Copy link
Copy Markdown
Member

Fixes an issue Titian Cernicova-Dragomir (@dragomirtitian) brought up around the JS max string size (!) for large batches of request responses. On the API client side, there's a maxResponseBytesPerPage option that's passed thru to the server with batch requests to limit response sizes , but the server has a default value of 300,000,000 bytes (which is a nice round number just under 66% of the v8 default string max size - to account for base64 encoding overhead) if that's not provided. Paged server responses are automatically reassembled into the full response objects back on the JS end, so nobody should really have to think about the protocol-level pagination.

This gets a little weird on the server-side to avoid double-encoding the response messages. Specifically, we have to encode the individual messages early so we can get their size and decide where to paginate and then custom-encode the batch response to be able to directly inline the already-encoded nested response objects. All fine enough things to do, I think, just a little weird compared to other API responses.

A small aside, but this PR also forbids nesting batchRequest protocol methods within batchRequest calls - the client already flattens incoming generators, and forbidding it makes pagination much simpler, so seems preferable to complicating pagination further.

async connect(): Promise<void> {
if (this.connected) return;
connect(): Promise<void> {
if (this.connected) return Promise.resolve();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Somehow the new large-file stress test actually triggered the hang (when used in conjunction with the full suite of API tests) that copilot found a few PRs ago so I went ahead and fixed it here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds transparent pagination for large batch API responses.

Changes:

  • Adds server-side paging and continuation tokens.
  • Reassembles pages in synchronous and asynchronous clients.
  • Adds protocol types, options, and pagination tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tsc/internal/api/session.go Implements pagination and continuation storage.
tsc/internal/api/session_batch_test.go Tests server pagination behavior.
tsc/internal/api/proto.go Extends and custom-encodes the batch protocol.
packages/typescript/src/api/sync/client.ts Reassembles paginated synchronous responses.
packages/typescript/src/api/async/client.ts Reassembles asynchronous responses and deduplicates connection attempts.
packages/typescript/src/api/proto.ts Excludes nested batch requests from request types.
packages/typescript/src/api/proto.generated.ts Adds pagination protocol fields.
packages/typescript/src/api/options.ts Exposes the response-page size option.
packages/typescript/test/sync/api-generators.test.ts Tests synchronous pagination.
packages/typescript/test/async/api.test.ts Tests asynchronous pagination.
Suppressed comments (1)

packages/typescript/src/api/options.ts:25

  • This is not a strict maximum: the server deliberately returns an intact response when one item alone exceeds the limit (see the added oversized-single-response test). Document that exception so callers do not rely on this option to guarantee that every decoded page stays below a hard transport/string-size ceiling.
    /** Maximum encoded byte size of each batch response page. Defaults to 300 million bytes. */
    maxResponseBytesPerPage?: number;

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +975 to +977
s.batchResponsePages.Store(continuationToken, batchResponsePage{
encodedResponses: slices.Clone(page.encodedResponses[pageLength:]),
})
pageParams.maxResponseBytesPerPage = this.maxResponseBytesPerPage;
}
const page = this.apiRequest("batchRequests", pageParams);
responses = responses.concat(page.responses);
pageParams.maxResponseBytesPerPage = this.options.maxResponseBytesPerPage;
}
const page = await this.sendRequestWithTiming(requestType, pageParams);
responses = responses.concat(page.responses);
Comment on lines +975 to +977
s.batchResponsePages.Store(continuationToken, batchResponsePage{
encodedResponses: slices.Clone(page.encodedResponses[pageLength:]),
})
Comment on lines +11 to +12
/** Maximum encoded byte size of each batch response page. Defaults to 300 million bytes. */
maxResponseBytesPerPage?: number;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

2 participants