Additional generator-based sync API methods - #64023
Additional generator-based sync API methods#64023Wesley Wigham (weswigham) wants to merge 6 commits into
Conversation
Much more exhaustive sync batcher testing
e0c918c to
4f350d5
Compare
There was a problem hiding this comment.
Pull request overview
Adds generator-backed sync API methods and batching support while preserving direct synchronous calls.
Changes:
- Generates
.gen()variants for sync API methods. - Adds generator request batching and error propagation.
- Adds broad sync/generator parity tests and shared test utilities.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
packages/typescript/scripts/generateSync.ts |
Generates sync and generator-backed methods. |
packages/typescript/src/api/async/api.ts |
Refactors source API for generation. |
packages/typescript/src/api/sync/api.ts |
Contains generated generator-enabled APIs. |
packages/typescript/src/api/sync/generatorSupport.ts |
Executes batched request generators. |
packages/typescript/src/api/sync/types.ts |
Exposes typed .gen() methods. |
packages/typescript/test/async/api.test.ts |
Uses shared async test setup. |
packages/typescript/test/async/api.testUtils.ts |
Provides async test utilities. |
packages/typescript/test/sync/api.test.ts |
Uses shared sync test setup. |
packages/typescript/test/sync/api.testUtils.ts |
Provides sync test utilities. |
packages/typescript/test/sync/api-generators.test.ts |
Tests batching and API parity. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| if ( | ||
| ts.isCallExpression(node.expression) && | ||
| ts.isPropertyAccessExpression(node.expression.expression) && | ||
| ts.isPropertyAccessExpression(node.expression.expression.expression) && | ||
| node.expression.expression.expression.name.text === "client" | ||
| ) { | ||
| return getTextWithOwner(node.expression); |
There was a problem hiding this comment.
Sync binary requests can't batch anyway (rip), so this is actually fine. A feature, even. Were we to force the issue, we'd have to double decode the AST payload, which sounds terrible (once into a base64 blob in the json batch response, then again into a buffer). This is one of those cases where a bespoke getSourceFiles API with proper encoder support for the direct binary response would be good.
| const state = result.error | ||
| ? requestGenerator.throw(new Error(result.error)) | ||
| : requestGenerator.next(result.result); |
There was a problem hiding this comment.
Maintaining control flow just for finally cleanup blocks in the case where a subset of a batch requests has an unhandled throw is some gnarly morally reentrant state management. Like, it can be done, but I don't really like the shape it takes to do what it has to do. See here. Like - sending follow-up requests from sibling batch requests after an unhandled failure result from the server kills the whole batch? Just seems wrong.
How about we just don't, and acknowledge exceptions are exceptional? Expecting all your other requests in a batch to exit and cleanup normally when one has an unhandled exception seems rough. I'm willing to state it here: "If one request in a batch throws an unhandled (server) exception, other generators in the batch will not continue or cleanup" - There. Now it's an API consumer's problem if they use exceptions for control flow. I'm not even sure that the API client is safe to keep using if the server yields an error response for one of the methods in a batch.
…wn on IPC traffic pretty easily on big first-request batches
|
This is the version we have: https://gist.github.com/dragomirtitian/150926e5900e995771f1618f72051c25 The version I have here allows for composability of functions that use the batching. Is there the possibility to do that in the version in this PR? From what I see the We were thinking of open sourcing it as a general library not tied to TSAPI, but if it's build into TS might not really be needed. |
|
|
…equests`, test user-composed generator functions
|
Cool, I've extracted the |
Basically, this adds a strongly typed
method for every
method. This make it very easy to write a nice to use sync request batching function which runs those generators to produce batched requests, like
which is also included for the
syncAPI here, giving it an omni-request-batching API that's pretty on-par with the async API experience.This is like the 3rd shape of this API I've tried and I like this one the most - the codegen complexity is just a bit high, so I'd like some feedback.
As an aside: Really, generators are the most flexible implementation construct here. We could just write the main API with generators and then write both the sync and async APIs as wrappers over it and do away with the async->sync codegen step entirely, but I still worry that generator object allocations are pricey for chatty non-batching API uses, which is why I still have both the straight sync and generator-based method implementations on the sync API (rather than implementing the sync API in terms of the generator one).
cc Titian Cernicova-Dragomir (@dragomirtitian) I think this probably roughly aligns with what you said you'd been building to enable batching internally.