From b30e9332fcf1c174af789b3d425925e8498ee349 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Mon, 17 Dec 2018 16:59:11 +0200 Subject: [PATCH 01/14] Cache successfully parsed and validated documents for future requests. WIP --- .../apollo-server-core/src/ApolloServer.ts | 21 +++ .../src/__tests__/runQuery.test.ts | 164 ++++++++++++++++++ .../apollo-server-core/src/graphqlOptions.ts | 3 +- .../apollo-server-core/src/requestPipeline.ts | 77 +++++--- .../apollo-server-core/src/runHttpQuery.ts | 1 + 5 files changed, 242 insertions(+), 24 deletions(-) diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 8d81e2f0794..db56cf655ba 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -9,6 +9,7 @@ import { GraphQLFieldResolver, ValidationContext, FieldDefinitionNode, + DocumentNode, } from 'graphql'; import { GraphQLExtension } from 'graphql-extensions'; import { EngineReportingAgent } from 'apollo-engine-reporting'; @@ -114,6 +115,11 @@ export class ApolloServerBase { // the default version is specified in playground.ts protected playgroundOptions?: PlaygroundRenderPageOptions; + // An optionally defined store that, when enabled (default), will store the + // parsed and validated versions of operations in-memory, allowing subsequent + // parse and validates on the same operation to be executed immediately. + private documentStore?: InMemoryLRUCache; + // The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods constructor(config: Config) { if (!config) throw new Error('ApolloServer requires options.'); @@ -136,6 +142,9 @@ export class ApolloServerBase { ...requestOptions } = config; + // Initialize the document store. This cannot currently be disabled. + this.initializeDocumentStore(); + // Plugins will be instantiated if they aren't already, and this.plugins // is populated accordingly. this.ensurePluginInstantiation(plugins); @@ -486,6 +495,17 @@ export class ApolloServerBase { }); } + private initializeDocumentStore(): void { + this.documentStore = new InMemoryLRUCache({ + // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise + // since the technique to calculate the size of a DocumentNode is + // only using JSON.stringify on the DocumentNode (and thus doesn't account + // for unicode characters, etc.), but it should do a reasonable job at + // providing a caching document store for most operations. + maxSize: Math.pow(2, 20) * 30, + }); + } + // This function is used by the integrations to generate the graphQLOptions // from an object containing the request and other integration specific // options @@ -509,6 +529,7 @@ export class ApolloServerBase { return { schema: this.schema, plugins: this.plugins, + documentStore: this.documentStore, extensions: this.extensions, context, // Allow overrides from options. Be explicit about a couple of them to diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index d18f1b2517e..97c7920ed36 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -20,6 +20,11 @@ import { import { processGraphQLRequest, GraphQLRequest } from '../requestPipeline'; import { Request } from 'apollo-server-env'; import { GraphQLOptions, Context as GraphQLContext } from 'apollo-server-core'; +import { + ApolloServerPlugin, + GraphQLRequestListener, +} from 'apollo-server-plugin-base'; +import { InMemoryLRUCache } from 'apollo-server-caching'; // This is a temporary kludge to ensure we preserve runQuery behavior with the // GraphQLRequestProcessor refactoring. @@ -49,10 +54,12 @@ interface QueryOptions | 'cacheControl' | 'context' | 'debug' + | 'documentStore' | 'extensions' | 'fieldResolver' | 'formatError' | 'formatResponse' + | 'plugins' | 'rootValue' | 'schema' | 'tracing' @@ -444,6 +451,163 @@ describe('runQuery', () => { }); }); + describe('parsing and validation cache', () => { + function createLifecyclePluginMocks() { + const validationDidStart = jest.fn(); + const parsingDidStart = jest.fn(); + + const plugins: ApolloServerPlugin[] = [ + { + requestDidStart() { + return { + validationDidStart, + parsingDidStart, + } as GraphQLRequestListener; + }, + }, + ]; + + return { + plugins, + events: { validationDidStart, parsingDidStart }, + }; + } + + function runRequest({ + queryString = '{ testString }', + plugins = [], + documentStore, + }: { + queryString?: string; + plugins?: ApolloServerPlugin[]; + documentStore?: QueryOptions['documentStore']; + }) { + return runQuery({ + schema, + documentStore, + queryString, + plugins, + request: new MockReq(), + }); + } + + function forgeLargerTestQuery( + count: number, + prefix: string = 'prefix', + ): string { + if (count <= 0) { + count = 1; + } + + let query: string = ''; + + for (let q = 0; q < count; q++) { + query += ` ${prefix}_${count}: testString\n`; + } + + return '{\n' + query + '}'; + } + + it('validates each time when the documentStore is not present', async () => { + expect.assertions(4); + + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + // The first request will do a parse and validate. (1/1) + await runRequest({ plugins }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + // The second request should ALSO do a parse and validate. (2/2) + await runRequest({ plugins }); + expect(parsingDidStart.mock.calls.length).toBe(2); + expect(validationDidStart.mock.calls.length).toBe(2); + }); + + it('caches the DocumentNode in the documentStore when instrumented', async () => { + expect.assertions(4); + const documentStore = new InMemoryLRUCache(); + + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + // An uncached request will have 1 parse and 1 validate call. + await runRequest({ plugins, documentStore }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + // The second request should still only have a 1 validate and 1 parse. + await runRequest({ plugins, documentStore }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + console.log(documentStore); + }); + + it("the documentStore calculates the DocumentNode's length by its JSON.stringify'd representation", async () => { + expect.assertions(14); + const { + plugins, + events: { parsingDidStart, validationDidStart }, + } = createLifecyclePluginMocks(); + + const queryLarge = forgeLargerTestQuery(3, 'large'); + const querySmall1 = forgeLargerTestQuery(1, 'small1'); + const querySmall2 = forgeLargerTestQuery(1, 'small2'); + + // We're going to create a smaller-than-default cache which will be the + // size of the two smaller queries. All three of these queries will never + // fit into this cache, so we'll roll through them all. + const maxSize = + JSON.stringify(parse(querySmall1)).length + + JSON.stringify(parse(querySmall2)).length; + + const documentStore = new InMemoryLRUCache({ maxSize }); + + await runRequest({ plugins, documentStore, queryString: querySmall1 }); + expect(parsingDidStart.mock.calls.length).toBe(1); + expect(validationDidStart.mock.calls.length).toBe(1); + + await runRequest({ plugins, documentStore, queryString: querySmall2 }); + expect(parsingDidStart.mock.calls.length).toBe(2); + expect(validationDidStart.mock.calls.length).toBe(2); + + // This query should be large enough to evict both of the previous + // from the LRU cache since it's larger than the TOTAL limit of the cache + // (which is capped at the length of small1 + small2) — though this will + // still fit (barely). + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(3); + expect(validationDidStart.mock.calls.length).toBe(3); + + // Make sure the large query is still cached (No incr. to parse/validate.) + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(3); + expect(validationDidStart.mock.calls.length).toBe(3); + + // This small (and the other) should both trigger parse/validate since + // the cache had to have evicted them both after accommodating the larger. + await runRequest({ plugins, documentStore, queryString: querySmall1 }); + expect(parsingDidStart.mock.calls.length).toBe(4); + expect(validationDidStart.mock.calls.length).toBe(4); + + await runRequest({ plugins, documentStore, queryString: querySmall2 }); + expect(parsingDidStart.mock.calls.length).toBe(5); + expect(validationDidStart.mock.calls.length).toBe(5); + + // Finally, make sure that the large query is gone (it should be, after + // the last two have take its spot again.) + await runRequest({ plugins, documentStore, queryString: queryLarge }); + expect(parsingDidStart.mock.calls.length).toBe(6); + expect(validationDidStart.mock.calls.length).toBe(6); + }); + }); + describe('async_hooks', () => { let asyncHooks: typeof import('async_hooks'); let asyncHook: import('async_hooks').AsyncHook; diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts index afed78ab98a..c1e36ffa2c6 100644 --- a/packages/apollo-server-core/src/graphqlOptions.ts +++ b/packages/apollo-server-core/src/graphqlOptions.ts @@ -6,7 +6,7 @@ import { } from 'graphql'; import { GraphQLExtension } from 'graphql-extensions'; import { CacheControlExtensionOptions } from 'apollo-cache-control'; -import { KeyValueCache } from 'apollo-server-caching'; +import { KeyValueCache, InMemoryLRUCache } from 'apollo-server-caching'; import { DataSource } from 'apollo-datasource'; import { ApolloServerPlugin } from 'apollo-server-plugin-base'; @@ -43,6 +43,7 @@ export interface GraphQLServerOptions< cache?: KeyValueCache; persistedQueries?: PersistedQueryOptions; plugins?: ApolloServerPlugin[]; + documentStore?: InMemoryLRUCache; } export type DataSources = { diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 7c4429c3f60..9c901cdda89 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -44,6 +44,7 @@ import { } from 'apollo-server-plugin-base'; import { Dispatcher } from './utils/dispatcher'; +import { InMemoryLRUCache } from 'apollo-server-caching'; export { GraphQLRequest, @@ -76,6 +77,7 @@ export interface GraphQLRequestPipelineConfig { formatResponse?: Function; plugins?: ApolloServerPlugin[]; + documentStore?: InMemoryLRUCache; } export type DataSources = { @@ -162,35 +164,64 @@ export async function processGraphQLRequest( requestContext, }); - const parsingDidEnd = await dispatcher.invokeDidStartHook( - 'parsingDidStart', - requestContext, - ); - try { - let document: DocumentNode; - try { - document = parse(query); - parsingDidEnd(); - } catch (syntaxError) { - parsingDidEnd(syntaxError); - return sendErrorResponse(syntaxError, SyntaxError); + // If we're configured with a document store, we'll utilize the hash of the + // operation in order to lookup a previously parsed-and-validated operation + // from that. A failure to retrieve anything from the cache simply means + // we're guaranteed to do the parsing and validation ourselves. + let document: DocumentNode | undefined; + + if (config.documentStore) { + document = await config.documentStore.get(queryHash); } - requestContext.document = document; + // If we still don't have a document, we'll need to parse and validate it. + // With success, we'll attempt to save it into the store for future use. + if (!document) { + const parsingDidEnd = await dispatcher.invokeDidStartHook( + 'parsingDidStart', + requestContext, + ); - const validationDidEnd = await dispatcher.invokeDidStartHook( - 'validationDidStart', - requestContext as WithRequired, - ); + try { + requestContext.document = document = parse(query); + parsingDidEnd(); + } catch (syntaxError) { + parsingDidEnd(syntaxError); + return sendErrorResponse(syntaxError, SyntaxError); + } + + const validationDidEnd = await dispatcher.invokeDidStartHook( + 'validationDidStart', + requestContext as WithRequired, + ); - const validationErrors = validate(document); + const validationErrors = validate(document); - if (validationErrors.length === 0) { - validationDidEnd(); - } else { - validationDidEnd(validationErrors); - return sendErrorResponse(validationErrors, ValidationError); + if (validationErrors.length === 0) { + validationDidEnd(); + } else { + validationDidEnd(validationErrors); + return sendErrorResponse(validationErrors, ValidationError); + } + + if (config.documentStore) { + // The underlying cache store behind the `documentStore` returns a + // `Promise` which is resolved (or rejected), eventually, based on the + // success or failure (respectively) of the cache save attempt. While + // it's certainly possible to `await` this `Promise`, we don't care about + // whether or not its successful at this point. We'll instead proceed + // to serve the rest of the request and just hope that this works out. + // If it doesn't work, the next request will have another opportunity to + // try again. Errors will surface as warnings, as appropriate. + // + // While it shouldn't normally be necessary to wrap this `Promise` in a + // `Promise.resolve` invocation, it seems that the underlying cache store + // is returning a non-native `Promise` (e.g. Bluebird, etc.). + Promise.resolve(config.documentStore.set(queryHash, document)).catch( + err => console.warn('Could not store validated document.', err), + ); + } } // FIXME: If we want to guarantee an operation has been set when invoking diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts index 977593bcdd3..87da2ebd9ee 100644 --- a/packages/apollo-server-core/src/runHttpQuery.ts +++ b/packages/apollo-server-core/src/runHttpQuery.ts @@ -158,6 +158,7 @@ export async function runHttpQuery( | CacheControlExtensionOptions | undefined, dataSources: options.dataSources, + documentStore: options.documentStore, extensions: options.extensions, persistedQueries: options.persistedQueries, From 88a294b1784fa4fc01ac3b7f20ca6ffdc8ae182f Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 18 Dec 2018 17:12:23 +0200 Subject: [PATCH 02/14] Add CHANGELOG.md for #2111 (parse/validate document store/cache). --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f58fce271a9..2562cc66074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### v2.4.0-alpha + +- Implement an in-memory cache store to save parsed and validated documents and provide performance benefits for successful executions of the same document. [PR #2111](https://github.com/apollographql/apollo-server/pull/2111) + ### v2.3.1 - Provide types for `graphql-upload` in a location where they can be accessed by TypeScript consumers of `apollo-server` packages. [ccf935f9](https://github.com/apollographql/apollo-server/commit/ccf935f9) [Issue #2092](https://github.com/apollographql/apollo-server/issues/2092) From 7697623789a0c07cc65b496657d3e85bd96e1408 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 18 Dec 2018 17:14:02 +0200 Subject: [PATCH 03/14] Publish - apollo-cache-control@0.5.0-alpha.0 - apollo-datasource-rest@0.3.0-alpha.0 - apollo-datasource@0.3.0-alpha.0 - apollo-engine-reporting@0.3.0-alpha.0 - apollo-server-azure-functions@2.4.0-alpha.0 - apollo-server-cache-memcached@0.3.0-alpha.0 - apollo-server-cache-redis@0.3.0-alpha.0 - apollo-server-caching@0.3.0-alpha.0 - apollo-server-cloud-functions@2.4.0-alpha.0 - apollo-server-cloudflare@2.4.0-alpha.0 - apollo-server-core@2.4.0-alpha.0 - apollo-server-express@2.4.0-alpha.0 - apollo-server-hapi@2.4.0-alpha.0 - apollo-server-integration-testsuite@2.4.0-alpha.0 - apollo-server-koa@2.4.0-alpha.0 - apollo-server-lambda@2.4.0-alpha.0 - apollo-server-micro@2.4.0-alpha.0 - apollo-server-plugin-base@0.3.0-alpha.0 - apollo-server-testing@2.4.0-alpha.0 - apollo-server@2.4.0-alpha.0 - apollo-tracing@0.5.0-alpha.0 - graphql-extensions@0.5.0-alpha.0 --- packages/apollo-cache-control/package.json | 2 +- packages/apollo-datasource-rest/package.json | 2 +- packages/apollo-datasource/package.json | 2 +- packages/apollo-engine-reporting/package.json | 2 +- packages/apollo-server-azure-functions/package.json | 2 +- packages/apollo-server-cache-memcached/package.json | 2 +- packages/apollo-server-cache-redis/package.json | 2 +- packages/apollo-server-caching/package.json | 2 +- packages/apollo-server-cloud-functions/package.json | 2 +- packages/apollo-server-cloudflare/package.json | 2 +- packages/apollo-server-core/package.json | 2 +- packages/apollo-server-express/package.json | 2 +- packages/apollo-server-hapi/package.json | 2 +- packages/apollo-server-integration-testsuite/package.json | 2 +- packages/apollo-server-koa/package.json | 2 +- packages/apollo-server-lambda/package.json | 2 +- packages/apollo-server-micro/package.json | 2 +- packages/apollo-server-plugin-base/package.json | 2 +- packages/apollo-server-testing/package.json | 2 +- packages/apollo-server/package.json | 2 +- packages/apollo-tracing/package.json | 2 +- packages/graphql-extensions/package.json | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apollo-cache-control/package.json b/packages/apollo-cache-control/package.json index 0e59fac4d05..af164443134 100644 --- a/packages/apollo-cache-control/package.json +++ b/packages/apollo-cache-control/package.json @@ -1,6 +1,6 @@ { "name": "apollo-cache-control", - "version": "0.4.0", + "version": "0.5.0-alpha.0", "description": "A GraphQL extension for cache control", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-datasource-rest/package.json b/packages/apollo-datasource-rest/package.json index 353f7070964..efac3f6aff0 100644 --- a/packages/apollo-datasource-rest/package.json +++ b/packages/apollo-datasource-rest/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource-rest", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-datasource/package.json b/packages/apollo-datasource/package.json index 98fb98ab1cf..b667c625b76 100644 --- a/packages/apollo-datasource/package.json +++ b/packages/apollo-datasource/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-engine-reporting/package.json b/packages/apollo-engine-reporting/package.json index c823fb30f00..ba66efdf934 100644 --- a/packages/apollo-engine-reporting/package.json +++ b/packages/apollo-engine-reporting/package.json @@ -1,6 +1,6 @@ { "name": "apollo-engine-reporting", - "version": "0.2.0", + "version": "0.3.0-alpha.0", "description": "Send reports about your GraphQL services to Apollo Engine", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-server-azure-functions/package.json b/packages/apollo-server-azure-functions/package.json index 1ddb9fec9a8..f8d8db77b90 100644 --- a/packages/apollo-server-azure-functions/package.json +++ b/packages/apollo-server-azure-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-azure-functions", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Azure Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cache-memcached/package.json b/packages/apollo-server-cache-memcached/package.json index f575ca6d252..992c10cace9 100644 --- a/packages/apollo-server-cache-memcached/package.json +++ b/packages/apollo-server-cache-memcached/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-memcached", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-cache-redis/package.json b/packages/apollo-server-cache-redis/package.json index 50703b8c782..7bb11bbbeb7 100644 --- a/packages/apollo-server-cache-redis/package.json +++ b/packages/apollo-server-cache-redis/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-redis", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-caching/package.json b/packages/apollo-server-caching/package.json index 4d148b84fe0..125b2cc6c63 100644 --- a/packages/apollo-server-caching/package.json +++ b/packages/apollo-server-caching/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-caching", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-cloud-functions/package.json b/packages/apollo-server-cloud-functions/package.json index 869d2ab04a8..d6309eb6393 100644 --- a/packages/apollo-server-cloud-functions/package.json +++ b/packages/apollo-server-cloud-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloud-functions", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Google Cloud Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cloudflare/package.json b/packages/apollo-server-cloudflare/package.json index 1e222fba2eb..5598f5563f5 100644 --- a/packages/apollo-server-cloudflare/package.json +++ b/packages/apollo-server-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloudflare", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Cloudflare workers", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-core/package.json b/packages/apollo-server-core/package.json index 605e524d14f..07510574b41 100644 --- a/packages/apollo-server-core/package.json +++ b/packages/apollo-server-core/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-core", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Core engine for Apollo GraphQL server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-express/package.json b/packages/apollo-server-express/package.json index 06ff254a40a..a8ca5a4ca3d 100644 --- a/packages/apollo-server-express/package.json +++ b/packages/apollo-server-express/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-express", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Express and Connect", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-hapi/package.json b/packages/apollo-server-hapi/package.json index b04b20513b8..e4e6e261ac4 100644 --- a/packages/apollo-server-hapi/package.json +++ b/packages/apollo-server-hapi/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-hapi", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Hapi", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-integration-testsuite/package.json b/packages/apollo-server-integration-testsuite/package.json index 1d81058bc01..4985f912b03 100644 --- a/packages/apollo-server-integration-testsuite/package.json +++ b/packages/apollo-server-integration-testsuite/package.json @@ -1,7 +1,7 @@ { "name": "apollo-server-integration-testsuite", "private": true, - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Apollo Server Integrations testsuite", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-koa/package.json b/packages/apollo-server-koa/package.json index d5daa7a25e1..b5e93f7293a 100644 --- a/packages/apollo-server-koa/package.json +++ b/packages/apollo-server-koa/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-koa", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Koa", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-lambda/package.json b/packages/apollo-server-lambda/package.json index e5bfa84a82a..02cec714d8e 100644 --- a/packages/apollo-server-lambda/package.json +++ b/packages/apollo-server-lambda/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-lambda", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for AWS Lambda", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-micro/package.json b/packages/apollo-server-micro/package.json index 66f687638e5..6bb2b489e47 100644 --- a/packages/apollo-server-micro/package.json +++ b/packages/apollo-server-micro/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-micro", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production-ready Node.js GraphQL server for Micro", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-plugin-base/package.json b/packages/apollo-server-plugin-base/package.json index c8e4590cf41..cdd5e85f49e 100644 --- a/packages/apollo-server-plugin-base/package.json +++ b/packages/apollo-server-plugin-base/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-plugin-base", - "version": "0.2.1", + "version": "0.3.0-alpha.0", "description": "Apollo Server plugin base classes", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-testing/package.json b/packages/apollo-server-testing/package.json index e56a2d0b909..f53f6f29979 100644 --- a/packages/apollo-server-testing/package.json +++ b/packages/apollo-server-testing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-testing", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Test utils for apollo-server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server/package.json b/packages/apollo-server/package.json index 0f915e0ec3e..bf87c7c9deb 100644 --- a/packages/apollo-server/package.json +++ b/packages/apollo-server/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server", - "version": "2.3.1", + "version": "2.4.0-alpha.0", "description": "Production ready GraphQL Server", "author": "opensource@apollographql.com", "main": "dist/index.js", diff --git a/packages/apollo-tracing/package.json b/packages/apollo-tracing/package.json index 5a492d1ad78..559d2c2ca1a 100644 --- a/packages/apollo-tracing/package.json +++ b/packages/apollo-tracing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-tracing", - "version": "0.4.0", + "version": "0.5.0-alpha.0", "description": "Collect and expose trace data for GraphQL requests", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/graphql-extensions/package.json b/packages/graphql-extensions/package.json index a932e46f589..016ca1ec9f3 100644 --- a/packages/graphql-extensions/package.json +++ b/packages/graphql-extensions/package.json @@ -1,6 +1,6 @@ { "name": "graphql-extensions", - "version": "0.4.1", + "version": "0.5.0-alpha.0", "description": "Add extensions to GraphQL servers", "main": "./dist/index.js", "types": "./dist/index.d.ts", From 45f14a297151129ead30cf68e93b64a777cf02ce Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 15:58:25 +0200 Subject: [PATCH 04/14] Fix incorrect contraction in code comment, per feedback. Ref: https://github.com/apollographql/apollo-server/pull/2111/files#r247616489 --- packages/apollo-server-core/src/requestPipeline.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 9c901cdda89..8ded294a293 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -210,7 +210,7 @@ export async function processGraphQLRequest( // `Promise` which is resolved (or rejected), eventually, based on the // success or failure (respectively) of the cache save attempt. While // it's certainly possible to `await` this `Promise`, we don't care about - // whether or not its successful at this point. We'll instead proceed + // whether or not it's successful at this point. We'll instead proceed // to serve the rest of the request and just hope that this works out. // If it doesn't work, the next request will have another opportunity to // try again. Errors will surface as warnings, as appropriate. From f33ae19f6d54aae554432349a99768b3980e5b63 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 16:25:34 +0200 Subject: [PATCH 05/14] Ensure `requestContext.document` set, irregardless of `documentStore` use. Without this change, the `document` property was not set on the `requestContext` for consumption by request pipeline plugins. To further guard against this oversight, I've removed the extra `document` variable which was being used as scoped state for the document and switched to directly using (and assigning to) the `requestContext.document`. Nice catch, @glasser! Ref: https://github.com/apollographql/apollo-server/pull/2111/files#r247617469 --- .../apollo-server-core/src/requestPipeline.ts | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 8ded294a293..10249f33b18 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -169,22 +169,20 @@ export async function processGraphQLRequest( // operation in order to lookup a previously parsed-and-validated operation // from that. A failure to retrieve anything from the cache simply means // we're guaranteed to do the parsing and validation ourselves. - let document: DocumentNode | undefined; - if (config.documentStore) { - document = await config.documentStore.get(queryHash); + requestContext.document = await config.documentStore.get(queryHash); } // If we still don't have a document, we'll need to parse and validate it. // With success, we'll attempt to save it into the store for future use. - if (!document) { + if (!requestContext.document) { const parsingDidEnd = await dispatcher.invokeDidStartHook( 'parsingDidStart', requestContext, ); try { - requestContext.document = document = parse(query); + requestContext.document = parse(query); parsingDidEnd(); } catch (syntaxError) { parsingDidEnd(syntaxError); @@ -196,7 +194,7 @@ export async function processGraphQLRequest( requestContext as WithRequired, ); - const validationErrors = validate(document); + const validationErrors = validate(requestContext.document); if (validationErrors.length === 0) { validationDidEnd(); @@ -218,8 +216,10 @@ export async function processGraphQLRequest( // While it shouldn't normally be necessary to wrap this `Promise` in a // `Promise.resolve` invocation, it seems that the underlying cache store // is returning a non-native `Promise` (e.g. Bluebird, etc.). - Promise.resolve(config.documentStore.set(queryHash, document)).catch( - err => console.warn('Could not store validated document.', err), + Promise.resolve( + config.documentStore.set(queryHash, requestContext.document), + ).catch(err => + console.warn('Could not store validated document.', err), ); } } @@ -228,7 +228,10 @@ export async function processGraphQLRequest( // `willExecuteOperation` and executionDidStart`, we need to throw an // error here and not leave this to `buildExecutionContext` in // `graphql-js`. - const operation = getOperationAST(document, request.operationName); + const operation = getOperationAST( + requestContext.document, + request.operationName, + ); requestContext.operation = operation || undefined; // We'll set `operationName` to `null` for anonymous operations. @@ -255,7 +258,7 @@ export async function processGraphQLRequest( try { response = (await execute( - document, + requestContext.document, request.operationName, request.variables, )) as GraphQLResponse; From 2652057c33720937663c13bcc6fabaa9a0073ba2 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 16:29:06 +0200 Subject: [PATCH 06/14] Clarify comments surrounding `documentStore`, which led to confusion. The parsed/validated cache store is on by default. While it could be disabled, in theory, it cannot be disabled since its an internal property of the request pipeline processor class. See confusion here: https://github.com/withspectrum/spectrum/pull/4533#issuecomment-453446535 --- packages/apollo-server-core/src/ApolloServer.ts | 6 +++--- packages/apollo-server-core/src/requestPipeline.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index db56cf655ba..5f1db09fd13 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -115,9 +115,9 @@ export class ApolloServerBase { // the default version is specified in playground.ts protected playgroundOptions?: PlaygroundRenderPageOptions; - // An optionally defined store that, when enabled (default), will store the - // parsed and validated versions of operations in-memory, allowing subsequent - // parse and validates on the same operation to be executed immediately. + // A store that, when enabled (default), will store the parsed and validated + // versions of operations in-memory, allowing subsequent parses/validates + // on the same operation to be executed immediately. private documentStore?: InMemoryLRUCache; // The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 10249f33b18..6cffc2522f8 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -165,10 +165,10 @@ export async function processGraphQLRequest( }); try { - // If we're configured with a document store, we'll utilize the hash of the - // operation in order to lookup a previously parsed-and-validated operation - // from that. A failure to retrieve anything from the cache simply means - // we're guaranteed to do the parsing and validation ourselves. + // If we're configured with a document store (by default, we are), we'll + // utilize the operation's hash to lookup the AST from the previously + // parsed-and-validated operation. Failure to retrieve anything from the + // cache just means we're committed to doing the parsing and validation. if (config.documentStore) { requestContext.document = await config.documentStore.get(queryHash); } From f546086e95ad075148c79a256d35befd3d7ea411 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 16:38:51 +0200 Subject: [PATCH 07/14] Fix typos/spacing in commentary. Of my own making! --- packages/apollo-server-core/src/__tests__/runQuery.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index 97c7920ed36..325110a68b1 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -600,8 +600,8 @@ describe('runQuery', () => { expect(parsingDidStart.mock.calls.length).toBe(5); expect(validationDidStart.mock.calls.length).toBe(5); - // Finally, make sure that the large query is gone (it should be, after - // the last two have take its spot again.) + // Finally, make sure that the large query is gone (it should be, after + // the last two have taken its spot again.) await runRequest({ plugins, documentStore, queryString: queryLarge }); expect(parsingDidStart.mock.calls.length).toBe(6); expect(validationDidStart.mock.calls.length).toBe(6); From 1a9d65dd810e4bd47191c800c9b53a92c1ca6f88 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 16:41:09 +0200 Subject: [PATCH 08/14] Guard against (currently impossible) failure to read from `documentStore`. While the implementation of the `documentStore` is currently simple enough to never throw (it is in-memory), it makes some sense to guard against future extended functionality where an exception might be raised. Since storing this object in a distributed memory store isn't currently feasible, I'm not sure what such an exception would be right now, but I don't mind being proactive! Ref: https://github.com/apollographql/apollo-server/pull/2111/files#r247618501 --- packages/apollo-server-core/src/requestPipeline.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index 6cffc2522f8..d8313a304b4 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -170,7 +170,14 @@ export async function processGraphQLRequest( // parsed-and-validated operation. Failure to retrieve anything from the // cache just means we're committed to doing the parsing and validation. if (config.documentStore) { - requestContext.document = await config.documentStore.get(queryHash); + try { + requestContext.document = await config.documentStore.get(queryHash); + } catch (err) { + console.warn( + 'An error occurred while attempting to read from the documentStore.', + err, + ); + } } // If we still don't have a document, we'll need to parse and validate it. From 0879a1267e785ac6efc44826a4c5e81999a9ace8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 17:14:25 +0200 Subject: [PATCH 09/14] Be considerate of variable length utf-8 encodings in `InMemoryLRUCache`. Previously, this used the `JSON.stringify` length, but this is slightly more aware. --- packages/apollo-server-caching/src/InMemoryLRUCache.ts | 8 ++++---- .../apollo-server-core/src/__tests__/runQuery.test.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/apollo-server-caching/src/InMemoryLRUCache.ts b/packages/apollo-server-caching/src/InMemoryLRUCache.ts index b75dfcb37d0..2f6d1085923 100644 --- a/packages/apollo-server-caching/src/InMemoryLRUCache.ts +++ b/packages/apollo-server-caching/src/InMemoryLRUCache.ts @@ -13,14 +13,14 @@ export class InMemoryLRUCache implements KeyValueCache { return item.length; } - // If it's an object, we'll use the length to get an approximate, - // relative size of what it would take to store it. It's certainly not - // 100% accurate, but it's a very, very fast implementation and it + // If it's an object, we'll use JSON.stringify+Buffer.byteLength to + // approximate the size of what it would take to store. It's certainly + // not 100% accurate, but it should be a fast implementation which // doesn't require bringing in other dependencies or logic which we need // to maintain. In the future, we might consider something like: // npm.im/object-sizeof, but this should be sufficient for now. if (typeof item === 'object') { - return JSON.stringify(item).length; + return Buffer.byteLength(JSON.stringify(item), 'utf8'); } // Go with the lru-cache default "naive" size, in lieu anything better: diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index 325110a68b1..c75c376c2ae 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -508,6 +508,12 @@ describe('runQuery', () => { return '{\n' + query + '}'; } + // This should use the same logic as the calculation in InMemoryLRUCache: + // https://github.com/apollographql/apollo-server/blob/94b98ff3/packages/apollo-server-caching/src/InMemoryLRUCache.ts#L23 + function approximateObjectSize(obj: T): number { + return Buffer.byteLength(JSON.stringify(obj), 'utf8'); + } + it('validates each time when the documentStore is not present', async () => { expect.assertions(4); @@ -564,8 +570,8 @@ describe('runQuery', () => { // size of the two smaller queries. All three of these queries will never // fit into this cache, so we'll roll through them all. const maxSize = - JSON.stringify(parse(querySmall1)).length + - JSON.stringify(parse(querySmall2)).length; + approximateObjectSize(parse(querySmall1)) + + approximateObjectSize(parse(querySmall2)); const documentStore = new InMemoryLRUCache({ maxSize }); From be7162094c36f4ac9052a28a62afc479f718f0a6 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 15 Jan 2019 21:05:10 +0200 Subject: [PATCH 10/14] Shift the burden of object approximation into the `ApolloServerBase` class. The implementation of object-size approximation which is used for cache eviction purposes in the `InMemoryLRUCache` implementation (via `lru-cache`) was a short-term location for extensible logic which is better located within `ApolloServerBase`. This is particularly important since future logic may necessitate knowing or understanding the current size (roughly, memory usage) of the in-memory storage. Effective immediately, this adds support for providing a `dispose` function which is called when an object is purged from the cache to make room for another. --- .../src/InMemoryLRUCache.ts | 44 ++++++++++--------- .../apollo-server-core/src/ApolloServer.ts | 7 ++- .../src/__tests__/runQuery.test.ts | 5 ++- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/packages/apollo-server-caching/src/InMemoryLRUCache.ts b/packages/apollo-server-caching/src/InMemoryLRUCache.ts index 2f6d1085923..53f0e6bfc2c 100644 --- a/packages/apollo-server-caching/src/InMemoryLRUCache.ts +++ b/packages/apollo-server-caching/src/InMemoryLRUCache.ts @@ -1,32 +1,33 @@ import LRU from 'lru-cache'; import { KeyValueCache } from './KeyValueCache'; +function defaultLengthCalculation(item: any) { + if (Array.isArray(item) || typeof item === 'string') { + return item.length; + } + + // Go with the lru-cache default "naive" size, in lieu anything better: + // https://github.com/isaacs/node-lru-cache/blob/a71be6cd/index.js#L17 + return 1; +} + export class InMemoryLRUCache implements KeyValueCache { private store: LRU.Cache; // FIXME: Define reasonable default max size of the cache - constructor({ maxSize = Infinity }: { maxSize?: number } = {}) { + constructor({ + maxSize = Infinity, + sizeCalculator = defaultLengthCalculation, + onDispose, + }: { + maxSize?: number; + sizeCalculator?: (value: V, key: string) => number; + onDispose?: (key: string, value: V) => void; + } = {}) { this.store = new LRU({ max: maxSize, - length(item) { - if (Array.isArray(item) || typeof item === 'string') { - return item.length; - } - - // If it's an object, we'll use JSON.stringify+Buffer.byteLength to - // approximate the size of what it would take to store. It's certainly - // not 100% accurate, but it should be a fast implementation which - // doesn't require bringing in other dependencies or logic which we need - // to maintain. In the future, we might consider something like: - // npm.im/object-sizeof, but this should be sufficient for now. - if (typeof item === 'object') { - return Buffer.byteLength(JSON.stringify(item), 'utf8'); - } - - // Go with the lru-cache default "naive" size, in lieu anything better: - // https://github.com/isaacs/node-lru-cache/blob/a71be6cd/index.js#L17 - return 1; - }, + length: sizeCalculator, + dispose: onDispose, }); } @@ -43,4 +44,7 @@ export class InMemoryLRUCache implements KeyValueCache { async flush(): Promise { this.store.reset(); } + async getTotalSize() { + return this.store.length; + } } diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 5f1db09fd13..7aef4030b7a 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -93,6 +93,10 @@ function getEngineServiceId(engine: Config['engine']): string | undefined { const forbidUploadsForTesting = process && process.env.NODE_ENV === 'test' && !supportsUploadsInNode; +function approximateObjectSize(obj: T): number { + return Buffer.byteLength(JSON.stringify(obj), 'utf8'); +} + export class ApolloServerBase { public subscriptionsPath?: string; public graphqlPath: string = '/graphql'; @@ -496,13 +500,14 @@ export class ApolloServerBase { } private initializeDocumentStore(): void { - this.documentStore = new InMemoryLRUCache({ + this.documentStore = new InMemoryLRUCache({ // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise // since the technique to calculate the size of a DocumentNode is // only using JSON.stringify on the DocumentNode (and thus doesn't account // for unicode characters, etc.), but it should do a reasonable job at // providing a caching document store for most operations. maxSize: Math.pow(2, 20) * 30, + sizeCalculator: approximateObjectSize, }); } diff --git a/packages/apollo-server-core/src/__tests__/runQuery.test.ts b/packages/apollo-server-core/src/__tests__/runQuery.test.ts index c75c376c2ae..6c3d9804c29 100644 --- a/packages/apollo-server-core/src/__tests__/runQuery.test.ts +++ b/packages/apollo-server-core/src/__tests__/runQuery.test.ts @@ -573,7 +573,10 @@ describe('runQuery', () => { approximateObjectSize(parse(querySmall1)) + approximateObjectSize(parse(querySmall2)); - const documentStore = new InMemoryLRUCache({ maxSize }); + const documentStore = new InMemoryLRUCache({ + maxSize, + sizeCalculator: approximateObjectSize, + }); await runRequest({ plugins, documentStore, queryString: querySmall1 }); expect(parsingDidStart.mock.calls.length).toBe(1); From 7a0d0e6e96840bbf8cc85460b16a188877ebfd12 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Wed, 16 Jan 2019 13:07:17 +0200 Subject: [PATCH 11/14] [debug] Print out documentStore stats every 60 seconds. In an effort to see how effective this cache is in production during this alpha phase, we'll print out the stats on the document store every 60 seconds. --- .../apollo-server-core/src/ApolloServer.ts | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 7aef4030b7a..b942462fe68 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -500,15 +500,31 @@ export class ApolloServerBase { } private initializeDocumentStore(): void { - this.documentStore = new InMemoryLRUCache({ + let disposedInLastCycle = 0; + const maxSize = Math.pow(2, 20) * 30; + const documentStore = (this.documentStore = new InMemoryLRUCache< + DocumentNode + >({ // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise // since the technique to calculate the size of a DocumentNode is // only using JSON.stringify on the DocumentNode (and thus doesn't account // for unicode characters, etc.), but it should do a reasonable job at // providing a caching document store for most operations. - maxSize: Math.pow(2, 20) * 30, + maxSize, sizeCalculator: approximateObjectSize, - }); + onDispose() { + disposedInLastCycle += 1; + }, + })); + + setInterval(async () => { + const currentDocumentStoreSize = await documentStore.getTotalSize(); + const percent = Math.round((currentDocumentStoreSize / maxSize) * 100); + console.debug( + `[documentStore] ${currentDocumentStoreSize} / ${maxSize} (${percent}%). Disposed of ${disposedInLastCycle} documents this interval.`, + ); + disposedInLastCycle = 0; + }, 60000); } // This function is used by the integrations to generate the graphQLOptions From 33d1f828141826f4d874aa783fa302e381101ab5 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Wed, 16 Jan 2019 13:11:21 +0200 Subject: [PATCH 12/14] Publish - apollo-cache-control@0.5.0-alpha.1 - apollo-datasource-rest@0.3.0-alpha.1 - apollo-datasource@0.3.0-alpha.1 - apollo-engine-reporting@0.3.0-alpha.1 - apollo-server-azure-functions@2.4.0-alpha.1 - apollo-server-cache-memcached@0.3.0-alpha.1 - apollo-server-cache-redis@0.3.0-alpha.1 - apollo-server-caching@0.3.0-alpha.1 - apollo-server-cloud-functions@2.4.0-alpha.1 - apollo-server-cloudflare@2.4.0-alpha.1 - apollo-server-core@2.4.0-alpha.1 - apollo-server-express@2.4.0-alpha.1 - apollo-server-hapi@2.4.0-alpha.1 - apollo-server-integration-testsuite@2.4.0-alpha.1 - apollo-server-koa@2.4.0-alpha.1 - apollo-server-lambda@2.4.0-alpha.1 - apollo-server-micro@2.4.0-alpha.1 - apollo-server-plugin-base@0.3.0-alpha.1 - apollo-server-testing@2.4.0-alpha.1 - apollo-server@2.4.0-alpha.1 - apollo-tracing@0.5.0-alpha.1 - graphql-extensions@0.5.0-alpha.1 --- packages/apollo-cache-control/package.json | 2 +- packages/apollo-datasource-rest/package.json | 2 +- packages/apollo-datasource/package.json | 2 +- packages/apollo-engine-reporting/package.json | 2 +- packages/apollo-server-azure-functions/package.json | 2 +- packages/apollo-server-cache-memcached/package.json | 2 +- packages/apollo-server-cache-redis/package.json | 2 +- packages/apollo-server-caching/package.json | 2 +- packages/apollo-server-cloud-functions/package.json | 2 +- packages/apollo-server-cloudflare/package.json | 2 +- packages/apollo-server-core/package.json | 2 +- packages/apollo-server-express/package.json | 2 +- packages/apollo-server-hapi/package.json | 2 +- packages/apollo-server-integration-testsuite/package.json | 2 +- packages/apollo-server-koa/package.json | 2 +- packages/apollo-server-lambda/package.json | 2 +- packages/apollo-server-micro/package.json | 2 +- packages/apollo-server-plugin-base/package.json | 2 +- packages/apollo-server-testing/package.json | 2 +- packages/apollo-server/package.json | 2 +- packages/apollo-tracing/package.json | 2 +- packages/graphql-extensions/package.json | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/apollo-cache-control/package.json b/packages/apollo-cache-control/package.json index af164443134..eb19d742ceb 100644 --- a/packages/apollo-cache-control/package.json +++ b/packages/apollo-cache-control/package.json @@ -1,6 +1,6 @@ { "name": "apollo-cache-control", - "version": "0.5.0-alpha.0", + "version": "0.5.0-alpha.1", "description": "A GraphQL extension for cache control", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-datasource-rest/package.json b/packages/apollo-datasource-rest/package.json index efac3f6aff0..13ec7f928e5 100644 --- a/packages/apollo-datasource-rest/package.json +++ b/packages/apollo-datasource-rest/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource-rest", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-datasource/package.json b/packages/apollo-datasource/package.json index b667c625b76..c1e5476bb78 100644 --- a/packages/apollo-datasource/package.json +++ b/packages/apollo-datasource/package.json @@ -1,6 +1,6 @@ { "name": "apollo-datasource", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-engine-reporting/package.json b/packages/apollo-engine-reporting/package.json index ba66efdf934..9736a3bddb6 100644 --- a/packages/apollo-engine-reporting/package.json +++ b/packages/apollo-engine-reporting/package.json @@ -1,6 +1,6 @@ { "name": "apollo-engine-reporting", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "description": "Send reports about your GraphQL services to Apollo Engine", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/apollo-server-azure-functions/package.json b/packages/apollo-server-azure-functions/package.json index f8d8db77b90..460c925b97b 100644 --- a/packages/apollo-server-azure-functions/package.json +++ b/packages/apollo-server-azure-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-azure-functions", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Azure Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cache-memcached/package.json b/packages/apollo-server-cache-memcached/package.json index 992c10cace9..8e4d5df3b96 100644 --- a/packages/apollo-server-cache-memcached/package.json +++ b/packages/apollo-server-cache-memcached/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-memcached", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-cache-redis/package.json b/packages/apollo-server-cache-redis/package.json index 7bb11bbbeb7..eb49a61a8a8 100644 --- a/packages/apollo-server-cache-redis/package.json +++ b/packages/apollo-server-cache-redis/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cache-redis", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-caching/package.json b/packages/apollo-server-caching/package.json index 125b2cc6c63..b605aa38ad3 100644 --- a/packages/apollo-server-caching/package.json +++ b/packages/apollo-server-caching/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-caching", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "author": "opensource@apollographql.com", "license": "MIT", "repository": { diff --git a/packages/apollo-server-cloud-functions/package.json b/packages/apollo-server-cloud-functions/package.json index d6309eb6393..cb458ee943e 100644 --- a/packages/apollo-server-cloud-functions/package.json +++ b/packages/apollo-server-cloud-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloud-functions", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Google Cloud Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cloudflare/package.json b/packages/apollo-server-cloudflare/package.json index 5598f5563f5..56c2e6c6262 100644 --- a/packages/apollo-server-cloudflare/package.json +++ b/packages/apollo-server-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloudflare", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Cloudflare workers", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-core/package.json b/packages/apollo-server-core/package.json index baf11dade25..ec579d45067 100644 --- a/packages/apollo-server-core/package.json +++ b/packages/apollo-server-core/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-core", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Core engine for Apollo GraphQL server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-express/package.json b/packages/apollo-server-express/package.json index a8ca5a4ca3d..94f62902266 100644 --- a/packages/apollo-server-express/package.json +++ b/packages/apollo-server-express/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-express", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Express and Connect", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-hapi/package.json b/packages/apollo-server-hapi/package.json index e4e6e261ac4..690844f0d24 100644 --- a/packages/apollo-server-hapi/package.json +++ b/packages/apollo-server-hapi/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-hapi", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Hapi", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-integration-testsuite/package.json b/packages/apollo-server-integration-testsuite/package.json index 4985f912b03..e790f32c17e 100644 --- a/packages/apollo-server-integration-testsuite/package.json +++ b/packages/apollo-server-integration-testsuite/package.json @@ -1,7 +1,7 @@ { "name": "apollo-server-integration-testsuite", "private": true, - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Apollo Server Integrations testsuite", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-koa/package.json b/packages/apollo-server-koa/package.json index b5e93f7293a..cb260d8cf5a 100644 --- a/packages/apollo-server-koa/package.json +++ b/packages/apollo-server-koa/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-koa", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Koa", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-lambda/package.json b/packages/apollo-server-lambda/package.json index 02cec714d8e..3ff57cd97b5 100644 --- a/packages/apollo-server-lambda/package.json +++ b/packages/apollo-server-lambda/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-lambda", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for AWS Lambda", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-micro/package.json b/packages/apollo-server-micro/package.json index 6bb2b489e47..593ed2927a7 100644 --- a/packages/apollo-server-micro/package.json +++ b/packages/apollo-server-micro/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-micro", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production-ready Node.js GraphQL server for Micro", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-plugin-base/package.json b/packages/apollo-server-plugin-base/package.json index cdd5e85f49e..7548a9f2bd7 100644 --- a/packages/apollo-server-plugin-base/package.json +++ b/packages/apollo-server-plugin-base/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-plugin-base", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "description": "Apollo Server plugin base classes", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-testing/package.json b/packages/apollo-server-testing/package.json index f53f6f29979..5d2747d1707 100644 --- a/packages/apollo-server-testing/package.json +++ b/packages/apollo-server-testing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-testing", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Test utils for apollo-server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server/package.json b/packages/apollo-server/package.json index bf87c7c9deb..4206b797b1b 100644 --- a/packages/apollo-server/package.json +++ b/packages/apollo-server/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server", - "version": "2.4.0-alpha.0", + "version": "2.4.0-alpha.1", "description": "Production ready GraphQL Server", "author": "opensource@apollographql.com", "main": "dist/index.js", diff --git a/packages/apollo-tracing/package.json b/packages/apollo-tracing/package.json index 559d2c2ca1a..3b50d8e693a 100644 --- a/packages/apollo-tracing/package.json +++ b/packages/apollo-tracing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-tracing", - "version": "0.5.0-alpha.0", + "version": "0.5.0-alpha.1", "description": "Collect and expose trace data for GraphQL requests", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/graphql-extensions/package.json b/packages/graphql-extensions/package.json index 016ca1ec9f3..9d62713e952 100644 --- a/packages/graphql-extensions/package.json +++ b/packages/graphql-extensions/package.json @@ -1,6 +1,6 @@ { "name": "graphql-extensions", - "version": "0.5.0-alpha.0", + "version": "0.5.0-alpha.1", "description": "Add extensions to GraphQL servers", "main": "./dist/index.js", "types": "./dist/index.d.ts", From 2ed1c0e074fd912e5286e8884321ecfa75d02749 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Wed, 16 Jan 2019 13:11:21 +0200 Subject: [PATCH 13/14] Revert (as intended!) "[debug] Print out documentStore stats every 60 seconds." This reverts commit 7a0d0e6e96840bbf8cc85460b16a188877ebfd12, as I intended when I originally introduced it. Ref: https://github.com/apollographql/apollo-server/pull/2111#issuecomment-454779949 --- .../apollo-server-core/src/ApolloServer.ts | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index b942462fe68..7aef4030b7a 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -500,31 +500,15 @@ export class ApolloServerBase { } private initializeDocumentStore(): void { - let disposedInLastCycle = 0; - const maxSize = Math.pow(2, 20) * 30; - const documentStore = (this.documentStore = new InMemoryLRUCache< - DocumentNode - >({ + this.documentStore = new InMemoryLRUCache({ // Create ~about~ a 30MiB InMemoryLRUCache. This is less than precise // since the technique to calculate the size of a DocumentNode is // only using JSON.stringify on the DocumentNode (and thus doesn't account // for unicode characters, etc.), but it should do a reasonable job at // providing a caching document store for most operations. - maxSize, + maxSize: Math.pow(2, 20) * 30, sizeCalculator: approximateObjectSize, - onDispose() { - disposedInLastCycle += 1; - }, - })); - - setInterval(async () => { - const currentDocumentStoreSize = await documentStore.getTotalSize(); - const percent = Math.round((currentDocumentStoreSize / maxSize) * 100); - console.debug( - `[documentStore] ${currentDocumentStoreSize} / ${maxSize} (${percent}%). Disposed of ${disposedInLastCycle} documents this interval.`, - ); - disposedInLastCycle = 0; - }, 60000); + }); } // This function is used by the integrations to generate the graphQLOptions From 1d0021933ecfc992c506ae7528fd9e4fde6c2944 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Wed, 23 Jan 2019 15:04:23 +0200 Subject: [PATCH 14/14] Publish - apollo-server-azure-functions@2.4.0-alpha.2 - apollo-server-cloud-functions@2.4.0-alpha.2 - apollo-server-cloudflare@2.4.0-alpha.2 - apollo-server-core@2.4.0-alpha.2 - apollo-server-express@2.4.0-alpha.2 - apollo-server-hapi@2.4.0-alpha.2 - apollo-server-integration-testsuite@2.4.0-alpha.2 - apollo-server-koa@2.4.0-alpha.2 - apollo-server-lambda@2.4.0-alpha.2 - apollo-server-micro@2.4.0-alpha.2 - apollo-server-plugin-base@0.3.0-alpha.2 - apollo-server-testing@2.4.0-alpha.2 - apollo-server@2.4.0-alpha.2 - graphql-extensions@0.5.0-alpha.2 --- packages/apollo-server-azure-functions/package.json | 2 +- packages/apollo-server-cloud-functions/package.json | 2 +- packages/apollo-server-cloudflare/package.json | 2 +- packages/apollo-server-core/package.json | 2 +- packages/apollo-server-express/package.json | 2 +- packages/apollo-server-hapi/package.json | 2 +- packages/apollo-server-integration-testsuite/package.json | 2 +- packages/apollo-server-koa/package.json | 2 +- packages/apollo-server-lambda/package.json | 2 +- packages/apollo-server-micro/package.json | 2 +- packages/apollo-server-plugin-base/package.json | 2 +- packages/apollo-server-testing/package.json | 2 +- packages/apollo-server/package.json | 2 +- packages/graphql-extensions/package.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/apollo-server-azure-functions/package.json b/packages/apollo-server-azure-functions/package.json index 460c925b97b..469be4b7ed6 100644 --- a/packages/apollo-server-azure-functions/package.json +++ b/packages/apollo-server-azure-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-azure-functions", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Azure Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cloud-functions/package.json b/packages/apollo-server-cloud-functions/package.json index cb458ee943e..9c18c029f1a 100644 --- a/packages/apollo-server-cloud-functions/package.json +++ b/packages/apollo-server-cloud-functions/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloud-functions", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Google Cloud Functions", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-cloudflare/package.json b/packages/apollo-server-cloudflare/package.json index 56c2e6c6262..af9a73c8600 100644 --- a/packages/apollo-server-cloudflare/package.json +++ b/packages/apollo-server-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-cloudflare", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Cloudflare workers", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-core/package.json b/packages/apollo-server-core/package.json index ec579d45067..bd39cb8e7f6 100644 --- a/packages/apollo-server-core/package.json +++ b/packages/apollo-server-core/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-core", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Core engine for Apollo GraphQL server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-express/package.json b/packages/apollo-server-express/package.json index 94f62902266..a4ffb93326f 100644 --- a/packages/apollo-server-express/package.json +++ b/packages/apollo-server-express/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-express", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Express and Connect", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-hapi/package.json b/packages/apollo-server-hapi/package.json index 690844f0d24..eb4c033a71b 100644 --- a/packages/apollo-server-hapi/package.json +++ b/packages/apollo-server-hapi/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-hapi", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Hapi", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-integration-testsuite/package.json b/packages/apollo-server-integration-testsuite/package.json index e790f32c17e..8a82db43919 100644 --- a/packages/apollo-server-integration-testsuite/package.json +++ b/packages/apollo-server-integration-testsuite/package.json @@ -1,7 +1,7 @@ { "name": "apollo-server-integration-testsuite", "private": true, - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Apollo Server Integrations testsuite", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-koa/package.json b/packages/apollo-server-koa/package.json index cb260d8cf5a..dc41d844f75 100644 --- a/packages/apollo-server-koa/package.json +++ b/packages/apollo-server-koa/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-koa", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Koa", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-lambda/package.json b/packages/apollo-server-lambda/package.json index 3ff57cd97b5..838ba36b011 100644 --- a/packages/apollo-server-lambda/package.json +++ b/packages/apollo-server-lambda/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-lambda", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for AWS Lambda", "keywords": [ "GraphQL", diff --git a/packages/apollo-server-micro/package.json b/packages/apollo-server-micro/package.json index 593ed2927a7..d2bfea1f6ec 100644 --- a/packages/apollo-server-micro/package.json +++ b/packages/apollo-server-micro/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-micro", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production-ready Node.js GraphQL server for Micro", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-plugin-base/package.json b/packages/apollo-server-plugin-base/package.json index 7548a9f2bd7..fb563947800 100644 --- a/packages/apollo-server-plugin-base/package.json +++ b/packages/apollo-server-plugin-base/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-plugin-base", - "version": "0.3.0-alpha.1", + "version": "0.3.0-alpha.2", "description": "Apollo Server plugin base classes", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server-testing/package.json b/packages/apollo-server-testing/package.json index 5d2747d1707..1d1f628dbcd 100644 --- a/packages/apollo-server-testing/package.json +++ b/packages/apollo-server-testing/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server-testing", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Test utils for apollo-server", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apollo-server/package.json b/packages/apollo-server/package.json index 4206b797b1b..4a7ba329cc0 100644 --- a/packages/apollo-server/package.json +++ b/packages/apollo-server/package.json @@ -1,6 +1,6 @@ { "name": "apollo-server", - "version": "2.4.0-alpha.1", + "version": "2.4.0-alpha.2", "description": "Production ready GraphQL Server", "author": "opensource@apollographql.com", "main": "dist/index.js", diff --git a/packages/graphql-extensions/package.json b/packages/graphql-extensions/package.json index 9d62713e952..185a9e22ee4 100644 --- a/packages/graphql-extensions/package.json +++ b/packages/graphql-extensions/package.json @@ -1,6 +1,6 @@ { "name": "graphql-extensions", - "version": "0.5.0-alpha.1", + "version": "0.5.0-alpha.2", "description": "Add extensions to GraphQL servers", "main": "./dist/index.js", "types": "./dist/index.d.ts",