Skip to content
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

Custom Executor, staticOnly cache control #7978

Conversation

andrewmcgivery
Copy link
Contributor

@andrewmcgivery andrewmcgivery commented Nov 4, 2024

  • Added ability to use a custom executor such as graphql-jit
  • Added staticOnly to cache control plugin to reduce overhead of willResolveField
  • Fix type issue with subscriptions plugin

Why?

These changes are to optimize general execution time and especially execution time for larger payloads.

Here is a comparison of the response time with a increasing response size. You can see that compared to the Apollo baseline, using Apollo + graphql-jit + staticOnly cache control mode results in a more than twice as fast response time when getting to larger response sizes. Even with smaller response sizes, there is a notable difference in response time.

Screenshot 2024-11-04 at 2 20 19 PM

How?

Custom Executor

Version 4 of Apollo Server removed the executor argument. This was due to it being a "legacy" option that used to be used for the Gateway. However, in the process of removing it, it also removed the option to drop in something like graphql-JIT.

GraphQL JIT is a drop in replacement for graphql-js when executing. It is pretty significantly faster when looking at benchmarks.

This change introduces an argument called customExecutor which allows it to be dropped in. E.g.:

const executor = (schema: GraphQLSchema, cacheSize = 2014, compilerOpts = {}) => {
  const cache = lru(cacheSize);
  return async ({ contextValue, document, operationName, request, queryHash }) => {
    const prefix = operationName || 'NotParametrized';
    const cacheKey = `${prefix}-${queryHash}`;
    let compiledQuery = cache.get(cacheKey);
    if (!compiledQuery) {
      const compilationResult = compileQuery(schema, document, operationName || undefined, compilerOpts);
      if (isCompiledQuery(compilationResult)) {
        compiledQuery = compilationResult;
        cache.set(cacheKey, compiledQuery);
      } else {
        // ...is ExecutionResult
        return compilationResult;
      }
    }

    return compiledQuery.query(undefined, contextValue, request.variables || {});
  };
};

const schema = buildSubgraphSchema([{ typeDefs, resolvers }]);

const server = new ApolloServer<BaseContext>({
  schema,
  customExecutor: executor(schema),
});

Static Only Cache Control

The Cache Control plugin plugin currently runs willResolveField on every single field. This can cause quite a bit of overhead, especially on larger response sizes. This hook is to allow for dynamic cache control hints to be set in resolvers.

Note:
This new "option" was previous suggested/hinted at in a code comment! https://github.com/apollographql/apollo-server/blob/main/packages/server/src/requestPipeline.ts#L422

This change introduces a staticOnly argument (default: false) to the ApolloServerPluginCacheControl plugin which allows opting out of dynamic cache hints. E.g.:

const server = new ApolloServer<BaseContext>({
  cache,
  documentStore: new InMemoryLRUCache<DocumentNode>(),
  plugins: [
    ApolloServerPluginCacheControl({ staticOnly: true }),
  ],
});

…aticOnly` to cache control plugin to reduce overhead of willResolveField, fix ype issue with subscriptions plugin
@svc-apollo-docs
Copy link
Collaborator

svc-apollo-docs commented Nov 4, 2024

✅ Docs Preview Ready

No new or changed pages found.

@glasser
Copy link
Member

glasser commented Nov 4, 2024

Can you split this into three PRs?

@andrewmcgivery
Copy link
Contributor Author

Split into 2 draft PRs:

#7980
#7981

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.

3 participants