Skip to content

Commit 21651bd

Browse files
authored
experimental: Allow query plan & parsed/validated document cach… (#3755)
* experimental: Allow adjusting of query plan & parsed/validated document cache. This introduces two experimental configuration options for existing internal cache stores: - `experimental_approximateDocumentStoreSizeMiB` is added to the `ApolloServer` constructor options and controls the _approximate_[1] size, in MiB, of the request pipeline document store, which is used to avoid repeated parsing and validation passes on queries which equate to the same `queryHash`[2]. - `experimental_approximateQueryPlanStoreMiB` is added to the `ApolloGateway` constructor options and controls the _approximate_[1] size of the query plan cache, which is used to avoid recalculation on repeated queries which equate to the same `queryHash`[2]. These are currently experimental because a more complete solution might more dynamically account for memory of various internal caches and vary their sizes based based on available memory and the overall server performance, rather than needing hard-coded values which are less than precise. [1]: "Approximate", because it's based on the `JSON.stringify`'d byte-length of the value being cached. [2]: The `queryHash` is a SHA-256 value of the incoming operation. * Add CHANGELOG.md for #3755. * docs: Add documentation for #3755.
1 parent e888fab commit 21651bd

File tree

7 files changed

+43
-2
lines changed

7 files changed

+43
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The version headers in this history reflect the versions of Apollo Server itself
99
- Move TContext generic from requestDidStart method to ApolloServerPlugin Interface [#3525](https://github.com/apollographql/apollo-server/pull/3525)
1010
- `apollo-server-express`: Support `CorsOptionsDelegate` type on `cors` parameter to `applyMiddleware`, to align with the supported type of the underlying [`cors`](https://npm.im/cors) middleware [itself](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/31483b781ac30f98bdf4d40a517e921f2fc2ce37/types/cors/index.d.ts#L32). [PR #3613](https://github.com/apollographql/apollo-server/pull/3613)
1111
- `apollo-server-core`: Allow asynchronous initialization of datasources: the `initialize` method on datasources may now return a Promise, which will be settled before any resolvers are called. [#3639](https://github.com/apollographql/apollo-server/pull/3639)
12+
- `apollo-server-core`: experimental: Allow configuration of the parsed/validated document store by introducing an `experimental_approximateDocumentStoreMiB` property to the `ApolloServer` constructor options which overrides the default cache size of 30MiB. [#3755](https://github.com/apollographql/apollo-server/pull/3755)
1213

1314
### v2.9.16
1415

docs/source/api/apollo-gateway.mdx

+12
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ example of using `ApolloGateway`, see [Implementing a federated graph](/federati
9191
If `true`, the gateway logs startup messages, along with the query plan for
9292
each incoming request. The default value is `false`.
9393

94+
* `experimental_approximateQueryPlanStoreMiB`: `number`
95+
96+
> **This property is experimental.** It may be removed or change at any time, even within a patch release.
97+
98+
When set, this sets the approximate size of the query plan store (in MiB).
99+
This cache is used to save query plans for re-use on subsequent queries
100+
which resolve to the same `queryHash` (a SHA-256 of incoming operation).
101+
102+
When this property is omitted, the cache is still enabled with a default
103+
size of 30MiB, which is generally sufficient unless the server is
104+
processing a high number of unique operations.
105+
94106
#### Returns
95107

96108
An `ApolloGateway` instance, which you then pass as the `gateway` configuration option to the `ApolloServer` constructor, like so:

docs/source/api/apollo-server.md

+13
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,19 @@ new ApolloServer({
144144

145145
Pass the integration-specific CORS options. `false` removes the CORS middleware and `true` uses the defaults. This option is only available to `apollo-server`. For other server integrations, place `cors` inside of `applyMiddleware`.
146146

147+
* `experimental_approximateDocumentStoreSizeMiB`: `number`
148+
149+
> **This property is experimental.** It may be removed or change at any time, even within a patch release.
150+
151+
When set, this sets the approximate size of the parsed/validated document
152+
store (in MiB). This cache is used to save the already parsed and validated
153+
`DocumentNode`s for re-use on subsequent queries which resolve to the same
154+
`queryHash` (a SHA-256 of incoming operation).
155+
156+
When this property is omitted, the cache is still enabled with a default
157+
size of 30MiB, which is generally sufficient unless the server is processing
158+
a high number of unique operations.
159+
147160
#### Returns
148161

149162
`ApolloServer`

packages/apollo-gateway/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Reduce interface expansion for types contained to a single service [#3582](https://github.com/apollographql/apollo-server/pull/3582)
88
* Instantiate one `CachedFetcher` per gateway instance. This resolves a condition where multiple federated gateways would utilize the same cache store could result in an `Expected undefined to be a GraphQLSchema` error. [#3704](https://github.com/apollographql/apollo-server/pull/3704)
99
* Gateway: minimize downstream request size [#3737](https://github.com/apollographql/apollo-server/pull/3737)
10+
* experimental: Allow configuration of the query plan store by introducing an `experimental_approximateQueryPlanStoreMiB` property to the `ApolloGateway` constructor options which overrides the default cache size of 30MiB. [#3755](https://github.com/apollographql/apollo-server/pull/3755)
1011

1112
# v0.11.6
1213

packages/apollo-gateway/src/index.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ interface GatewayConfigBase {
5858
experimental_updateServiceDefinitions?: Experimental_UpdateServiceDefinitions;
5959
experimental_didUpdateComposition?: Experimental_DidUpdateCompositionCallback;
6060
experimental_pollInterval?: number;
61+
experimental_approximateQueryPlanStoreMiB?: number;
6162
}
6263

6364
interface RemoteGatewayConfig extends GatewayConfigBase {
@@ -178,6 +179,8 @@ export class ApolloGateway implements GraphQLService {
178179
// how often service defs should be loaded/updated (in ms)
179180
protected experimental_pollInterval?: number;
180181

182+
private experimental_approximateQueryPlanStoreMiB?: number;
183+
181184
constructor(config?: GatewayConfig) {
182185
this.config = {
183186
// TODO: expose the query plan in a more flexible JSON format in the future
@@ -219,6 +222,9 @@ export class ApolloGateway implements GraphQLService {
219222
this.experimental_didUpdateComposition =
220223
config.experimental_didUpdateComposition;
221224

225+
this.experimental_approximateQueryPlanStoreMiB =
226+
config.experimental_approximateQueryPlanStoreMiB;
227+
222228
if (
223229
isManagedConfig(config) &&
224230
config.experimental_pollInterval &&
@@ -609,7 +615,9 @@ export class ApolloGateway implements GraphQLService {
609615
// only using JSON.stringify on the DocumentNode (and thus doesn't account
610616
// for unicode characters, etc.), but it should do a reasonable job at
611617
// providing a caching document store for most operations.
612-
maxSize: Math.pow(2, 20) * 30,
618+
maxSize:
619+
Math.pow(2, 20) *
620+
(this.experimental_approximateQueryPlanStoreMiB || 30),
613621
sizeCalculator: approximateObjectSize,
614622
});
615623
}

packages/apollo-server-core/src/ApolloServer.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ export class ApolloServerBase {
153153
/** @deprecated: This is undefined for servers operating as gateways, and will be removed in a future release **/
154154
protected schema?: GraphQLSchema;
155155
private toDispose = new Set<() => void>();
156+
private experimental_approximateDocumentStoreMiB:
157+
Config['experimental_approximateDocumentStoreMiB'];
156158

157159
// The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods
158160
constructor(config: Config) {
@@ -176,6 +178,7 @@ export class ApolloServerBase {
176178
playground,
177179
plugins,
178180
gateway,
181+
experimental_approximateDocumentStoreMiB,
179182
...requestOptions
180183
} = config;
181184

@@ -716,7 +719,9 @@ export class ApolloServerBase {
716719
// only using JSON.stringify on the DocumentNode (and thus doesn't account
717720
// for unicode characters, etc.), but it should do a reasonable job at
718721
// providing a caching document store for most operations.
719-
maxSize: Math.pow(2, 20) * 30,
722+
maxSize:
723+
Math.pow(2, 20) *
724+
(this.experimental_approximateDocumentStoreMiB || 30),
720725
sizeCalculator: approximateObjectSize,
721726
});
722727
}

packages/apollo-server-core/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ export interface Config extends BaseConfig {
112112
uploads?: boolean | FileUploadOptions;
113113
playground?: PlaygroundConfig;
114114
gateway?: GraphQLService;
115+
experimental_approximateDocumentStoreMiB?: number;
115116
}
116117

117118
export interface FileUploadOptions {

0 commit comments

Comments
 (0)