-
Notifications
You must be signed in to change notification settings - Fork 655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Query Batching for apollo-runtime
#3117
Implement Query Batching for apollo-runtime
#3117
Conversation
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchHttpCall.kt
Outdated
Show resolved
Hide resolved
requestBuilder.header(header, value) | ||
} | ||
|
||
// TODO add http cache headers (does it make sense for batch HTTP calls?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly, adding the HTTP cache headers felt weird since a batch can potentially be different between 2 runs, as the queries that will be batched is timing dependent. I guess one could get lucky and get the exact same batch (maybe for single query screens), in which case HTTP caching could come into play. Let us know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it doesn't make a lot of sense to have HTTP cache + query batching. Ideally we could detect that HTTP + batching is used and throw an error. Maybe based on httpCachePolicy
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I'd say we need same kind of thing with AutoPersistedQueries too.
edit: and File Upload too...😅. Well for these last two we can rely on users not trying to activate them at the same time as batching. I think that's a fair expectation to have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we actually use APQ with batching and that works really well :)
Yeah I'll do the same for file uploads, throw an exception if used with batching with a clear message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we actually use APQ with batching and that works really well :)
Nice. Good to know 👍
Yeah I'll do the same for file uploads, throw an exception if used with batching with a clear message
File Uploads are a bit weird and work with reflexion at the moment. It might be a bit awkward to detect when it's used. If it becomes too convoluted, I think it's fine to leave that as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, since we're only enabling batching for queries and not mutations, is file upload even possible with queries? (never used it so not sure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and looking at http caching, since you can make non-batched queries with the same ApolloClient
, would be annoying to have to turn it off entirely if you still want your single queries to take advantage of it.
I'm thinking of just not adding the http cache headers for batch calls, and just silently ignore it. Not sure if I should log something to let the caller know?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is file upload even possible with queries?
In theory I think yes.. I don't see anything preventing someone to pass an Upload
custom scalar as a field argument. For an example a service that could sign your files using a server-side private key:
query GetSignature($file: Upload) {
signature(file: $file)
}
In practice, I've never seen anyone do that yet though...
we're only enabling batching for queries and not mutations
Would it make sense to enable batching for mutations? I don't think a theoretical reason to limit to queries?
looking at http caching, since you can make non-batched queries with the same ApolloClient, would be annoying to have to turn it off entirely if you still want your single queries to take advantage of it.
Right , makes sense 👍
I'm thinking of just not adding the http cache headers for batch calls, and just silently ignore it. Not sure if I should log something to let the caller know?
Could you do something per-query?
if (batchPoller != null) {
if (httpCachePolicy != null) {
throw new IllegalArgumentException("Using httpCachePolicy and batching at the same time does not make sense");
}
interceptors.add(new ApolloBatchingInterceptor(batchPoller));
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchPoller.kt
Outdated
Show resolved
Hide resolved
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchPoller.kt
Outdated
Show resolved
Hide resolved
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchPoller.kt
Show resolved
Hide resolved
apollo-runtime/src/main/java/com/apollographql/apollo/ApolloClient.java
Outdated
Show resolved
Hide resolved
Awesome contribution 😃 ! That'll make a lot of users happy and close the oldest open issue in this repo 🎉 . A few comments but looks good overall 👍 PS: I just pushed the metalava signatures used to enforce API compatibility. You can regenerate them with
|
Adding some unit tests next. |
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchPoller.kt
Outdated
Show resolved
Hide resolved
apollo-runtime/src/main/java/com/apollographql/apollo/internal/batch/BatchPoller.kt
Outdated
Show resolved
Hide resolved
apollo-integration/src/test/java/com/apollographql/apollo/internal/batch/BatchPollerTest.kt
Show resolved
Hide resolved
@martinbonnin feeling pretty good about the latest implementation and tests, let me know what you think! |
Thanks for adding more tests! A couple of remaining comments:
|
Yeah I hesitated between controlling the time or testing the automatic trigger, I'll switch it to a more controlled test
Great suggestion, should have thought of it earlier!
Still torn on that, it should work fine I think but since mutations are usually slower and more isolated one-offs in general, it feels a bit weird to mix them with queries? But yeah as you mentioned, can easily be enabled later if needed. |
@martinbonnin should I add |
Yup, you're right 👍 . |
running metalava locally is changing way more signatures that it should for some reasons, mind running it for me? |
Done. Not sure why but metalava signatures depend on the local JVM. I have to use JDK8 to get signatures matching the CI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Thanks @joaquim-verges for the awesome contribution! |
Glad I could help! |
* Add a "Who is Apollo" section to the main README (#3073) * Slight tweaks to the "Who is Apollo?" README section (#3079) To align with apollographql/apollo-client#8079. * Update dependency gatsby-theme-apollo-docs to v4.7.3 * Issue #3095: Expose channel capacity parameter. (#3096) Co-authored-by: Neal Sanche <[email protected]> * Update dependency gatsby to v2.32.13 * Update dependency gatsby-theme-apollo-docs to v4.7.4 * Fix Float input fields Java codegen with default values in json schemas (#3109) * Fix Float input fields Java codegen with default values in json schemas see #3108 * add a test case for lists in defaultValues and handle it Co-authored-by: Martin Bonnin <[email protected]> * bump Kotlin and Coroutines to 1.5.0 (#3113) * bump Kotlin and Coroutines to 1.5.0 * make the KotlinCompile task depend on antlr generation * update metalava-plugin * update metalava * update metalava using Jdk8. Not really sure why the signatures would differ based on the java version... * release 2.5.7 * version is now 2.5.8-SNAPSHOT * Update README.md (#3120) * Replace spectrum with discourse (#3123) * Discourse: pre-fill the category and tags * Update multi-modules.mdx (#3125) * Implement Query Batching for `apollo-runtime` (#3117) * Implement Query Batching for `apollo-runtime` * update metalava signatures * Trigger HTTP call on max batch size, added synchronization, throw when using GET method * Unit tests for BatchPoller * Fix checkstyle * Propagate parsing errors in callbacks, better syncrhonization, use LinkedList * Added some tests for batch response parsing * Added tests for request body + headers * Builder API to enable per query batching, dont rely on time for tests * update Metalava signatures Co-authored-by: Martin Bonnin <[email protected]> * pass 'operationName' in the introspection query (#3126) * bump junit (#3131) * Update dependency gatsby-theme-apollo-docs to v4.7.6 * feat: add Reactor support (#3138) * feat: add Reactor support resolves #627 * remove .gitignore that is handled by the top level one * update metalava signatures Co-authored-by: Martin Bonnin <[email protected]> * Update dependency gatsby-theme-apollo-docs to v4.7.9 * add reactor in the left column of the doc (#3141) * release 2.5.8 * version is now 2.5.9-SNAPSHOT * Fix overriding `canBeBatched` value when cloning `QueryCall` with `toBuilder()` (#3146) * Update get-started-multiplatform.mdx (#3150) update dep version forcing as per gradle new api * Update badge from Bintray to MavenCentral for apollo-idling-resource (#3153) Thanks! * Update 09-write-your-first-mutation.mdx (#3154) * Update 01-configure-project.mdx * Update 02-add-the-graphql-schema.mdx * release 2.5.9 * version is now 2.5.10-SNAPSHOT * refactor: RxJava 2/3 support (#3166) * Update dependency striptags to 3.2.0 [SECURITY] (#3178) Co-authored-by: Renovate Bot <[email protected]> * Update dependency gatsby-theme-apollo-docs to v4.7.11 * Update dependency gatsby-theme-apollo-docs to v4.7.12 * remove duplicate executionContext (#3213) * feat: add Mutiny support (#3198) * feat: add Mutiny support * Update gatsby-config.js Co-authored-by: Martin Bonnin <[email protected]> * add v3 docs (#3223) * Add 3.0 alpha notice (#3231) * Update dependency gatsby-theme-apollo-docs to v4.7.13 * July 2021 ROADMAP update (#3255) * Update ROADMAP.md * Update dependency gatsby-theme-apollo-docs to v4.7.14 * Update multi-modules.mdx Add a not about multi platform, See #3297 * Update multi-modules.mdx Remove deleted branch * Replace Spectrum with community.apollographql.com (#3299) * Update ROADMAP.md * Update dependency path-parse to 1.0.7 [SECURITY] (#3296) Co-authored-by: Renovate Bot <[email protected]> * Update dependency gatsby-theme-apollo-docs to v4.7.15 * Remove root redirect and build deploy previews at / (#3309) * Deploy the prod site at the root (#3312) * Update dependency gatsby-theme-apollo-docs to v4.7.16 * Remove path prefixes for docs redirects (#3329) * Updated coroutines for use native-mt version (#3330) * Updated coroutines for use native-mt version * Update get-started-multiplatform.mdx Co-authored-by: Martin Bonnin <[email protected]> * Update dependency gatsby-theme-apollo-docs to v4.7.18 * Increase Json nesting to 256 (#3334) Closes #3308 * Bump docs theme to add Algolia search (#3346) * Configure for updated docs theme * Upgrade docs theme * Bump docs theme version * Bump docs theme version * Update docs theme version * Move config from docs netlify.toml to root level netlify.toml * Upgrade docs theme * Upgrade docs theme * Upgrade docs theme * Upgrade docs theme * Bump docs theme to v5 Co-authored-by: Trevor Blades <[email protected]> * Update dependency gatsby-theme-apollo-docs to v5.0.1 * Add Reactor && Mutiny to advanced topics (#3355) * feat: add Mutiny support * Update gatsby-config.js * doc: Add Reactor && Mutiny to advanced topics Co-authored-by: Martin Bonnin <[email protected]> * Update dependency gatsby-theme-apollo-docs to v5.0.2 * Update dependency gatsby-theme-apollo-docs to v5.0.3 * Update dependency gatsby-theme-apollo-docs to v5.0.7 * Who is Apollo README updates (#3379) Small updates to align "Who is Apollo" sections across repos. * Update dependency gatsby-theme-apollo-docs to v5.0.8 * Give a hint at errorPayload (#3381) See #3369 * docs: Configure custom Algolia filters (#3378) * Configure algolia filters * Upgrade theme * Upgrade theme * Adding Benoit (#3388) * Workaround wrong input field default values (#3398) * add a test case for #3394 * do not generate defaultValues for input fields of input object type * make an exception for emptyList for backward compatibility * do not crash when trying to indent the GraphQL document (#3399) * Minor improvements to the Tutorial documentation (#3396) * Minor improvements to the Tutorial documentation * Rephrase a sentence Co-authored-by: Martin Bonnin <[email protected]> * Remove unneeded dependency * Use 2.5.9 to be consistent with the code on tutorial's repo Co-authored-by: Martin Bonnin <[email protected]> * Add ./gradlew push${MainService}ApolloOperations (#3403) * add RegisterOperations * add ApolloRegisterOperationsTask * add a test case * fix bad copy/paste * update metalava signatures * add some doc * Update docs/source/advanced/operation-safelisting.mdx Co-authored-by: Benoit Lubek <[email protected]> * Update docs/source/advanced/operation-safelisting.mdx Co-authored-by: Benoit Lubek <[email protected]> * add the link to the operation registry server documentation Co-authored-by: Benoit Lubek <[email protected]> * Replace 'data graph' with 'graph' (#3389) * Operation Registry: normalize queries before computing the hash (#3406) * add normalization * be robust to Number.toString() in JS being different from Double.toString() in Java * remove extra "only" * workaround a doc issue where the 3.x was used instead of 2.x * release 2.5.10 * version is now 2.5.11-SNAPSHOT * Indicate the supported native platforms in the doc (2.x) (#3419) * Indicate the supported native platforms in the doc. * Clarification about the `js` target also being available * Added toString method for Input (#3427) * Fix outdated doc about FileUpload (#3429) * Update ROADMAP.md (#3445) * update ROADMAP.md * update ROADMAP.md * Update dependency gatsby-theme-apollo-docs to v5.3.1 * Make safelistingHash closer to its apollo-tooling counterpart (#3471) * take #2 on query normalization * added a comment * add comment * Update dependency gatsby-theme-apollo-docs to v5.3.2 * Update dependency gatsby-theme-apollo-docs to v5.3.3 * Update dependency url-parse to 1.5.2 [SECURITY] (#3522) Co-authored-by: Renovate Bot <[email protected]> * Update dependency ws to 7.4.6 [SECURITY] (#3523) Co-authored-by: Renovate Bot <[email protected]> * Update dependency ssri to 7.1.1 [SECURITY] (#3521) Co-authored-by: Renovate Bot <[email protected]> * Update dependency postcss to 7.0.36 [SECURITY] (#3519) Co-authored-by: Renovate Bot <[email protected]> * Update dependency object-path to 0.11.8 [SECURITY] (#3518) Co-authored-by: Renovate Bot <[email protected]> * Update dependency dns-packet to 1.3.2 [SECURITY] (#3517) Co-authored-by: Renovate Bot <[email protected]> * Update dependency browserslist to 4.16.5 [SECURITY] (#3516) Co-authored-by: Renovate Bot <[email protected]> * Update dependency axios to 0.21.2 [SECURITY] (#3515) Co-authored-by: Renovate Bot <[email protected]> * Bump docs theme and align React version w/ other docsets (#3539) * Always make sure the Response is closed (#3541) * release 2.5.11 * version is now 2.5.12-SNAPSHOT * Gateway clarification based on license change * Update dependency gatsby-theme-apollo-docs to v5.3.8 * update docs dependencies * pass 'operationName' in the introspection query (#3126) * update ROADMAP * add multiplatform in the multimodules doc * Remove root redirect and build deploy previews at / (#3309) * Deploy the prod site at the root (#3312) * Remove path prefixes for docs redirects (#3329) * add a Kotlin Native Doc inspired by commit 2e2f5d9 * Bump docs theme to add Algolia search (#3346) * Configure for updated docs theme * Upgrade docs theme * Bump docs theme version * Bump docs theme version * Update docs theme version * Move config from docs netlify.toml to root level netlify.toml * Upgrade docs theme * Upgrade docs theme * Upgrade docs theme * Upgrade docs theme * Bump docs theme to v5 Co-authored-by: Trevor Blades <[email protected]> * update algolia filters * Adding Benoit (#3388) * replace data graph with 'graph' * premliminary work for registerOperations * wip * wip * fix sorting * add Gradle tasks for registerOperations * add safelisting doc * update apiDump * revert debug and fix tests that require mpp-utils Co-authored-by: Danielle Man <[email protected]> Co-authored-by: Hugh Willson <[email protected]> Co-authored-by: Renovate Bot <[email protected]> Co-authored-by: Neal Sanche <[email protected]> Co-authored-by: Neal Sanche <[email protected]> Co-authored-by: Joaquim Verges <[email protected]> Co-authored-by: Moncef AOUDIA <[email protected]> Co-authored-by: Fabio Santo <[email protected]> Co-authored-by: Nicola Corti <[email protected]> Co-authored-by: Robert Theis <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Stephen Barlow <[email protected]> Co-authored-by: Trevor Blades <[email protected]> Co-authored-by: Виталий <[email protected]> Co-authored-by: Janessa Garrow <[email protected]> Co-authored-by: Benoit Lubek <[email protected]> Co-authored-by: Andrew Orobator <[email protected]>
Background
Hello Apollo team!
We, the Twitch Android team, have been using Apollo Android for 3+ years now, and have been very happy with it!
However, we recently ran into scalability issues in our app. Our most busy screen has exploded in features, where each feature is encapsulated and does its own GQL query. We've reached a point where that screen does 45 GQL queries (and therefore 45 HTTP calls) when it comes on screen 🤯 This is not only costly for the client, but also very costly for our backend services.
We explored grouping queries into larger ones, but we like the modularity and encapsulation that we have right now where each feature can do their fetching independently. We also know that our web team (who also uses Apollo) solved this problem by enabling batching for queries in the web Apollo client (and that our server supports it).
We decided to fork the Android library to implement the ability to batch multiple queries in a single HTTP call, similar to what the web client offers. We're about to test our implementation in production, and should will gather data in the next few weeks.
In the meantime, we thought it would be useful to push our implementation upstream and give back to the Apollo community!
Implementation
We followed the approach that the web Apollo client took, where batching is achieved by a "poller" that checks periodically for queries to be batched, packages them into a single request body and sends them to the server. On response, the response body is parsed to extract each sub-response and forwarded back to the corresponding callers.
The implementation below is the minimal one that we needed to get that approach working, and we're looking for early feedback before writing unit tests, samples and later port it to the
apollo-runtime-kotlin
artifact.Let us know what you think!