Skip to content

Custom Executor, staticOnly cache control#7978

Closed
andrewmcgivery wants to merge 1 commit into
apollographql:mainfrom
andrewmcgivery:feature/customExecutor
Closed

Custom Executor, staticOnly cache control#7978
andrewmcgivery wants to merge 1 commit into
apollographql:mainfrom
andrewmcgivery:feature/customExecutor

Conversation

@andrewmcgivery

@andrewmcgivery andrewmcgivery commented Nov 4, 2024

Copy link
Copy Markdown
Contributor
  • 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

svc-apollo-docs commented Nov 4, 2024

Copy link
Copy Markdown

✅ Docs Preview Ready

No new or changed pages found.

@glasser

glasser commented Nov 4, 2024

Copy link
Copy Markdown
Member

Can you split this into three PRs?

@andrewmcgivery

Copy link
Copy Markdown
Contributor Author

Split into 2 draft PRs:

#7980
#7981

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Dec 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants