Skip to content

Commit

Permalink
Merge pull request #2215 from apollographql/release-2.4.0
Browse files Browse the repository at this point in the history
Release 2.4.0
  • Loading branch information
abernix authored Feb 7, 2019
2 parents ce4e504 + f74610b commit c5b71f8
Show file tree
Hide file tree
Showing 31 changed files with 321 additions and 76 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Changelog

### vNEXT
### vNEXT (v2.4.0)

- Implement an in-memory cache store to save parsed and validated documents and provide performance benefits for repeat executions of the same document. [PR #2111](https://github.com/apollographql/apollo-server/pull/2111) (`>=2.4.0-alpha.0`)
- Fix: Serialize arrays as JSON on fetch in `RESTDataSource`. [PR #2219](https://github.com/apollographql/apollo-server/pull/2219)
- Fix: The `privateHeaders` configuration for `apollo-engine-reporting` now allows headers to be specified using any case and lower-cases them prior to comparison. [PR #2276](https://github.com/apollographql/apollo-server/pull/2276)

Expand Down Expand Up @@ -30,9 +31,9 @@
While Node.js 6.x is covered by a [Long Term Support agreement by the Node.js Foundation](https://github.com/nodejs/Release#release-schedule) until April 2019, there are substantial performance (e.g. [V8](https://v8.dev/) improvements) and language changes (e.g. "modern" ECMAScript support) offered by newer Node.js engines (e.g. 8.x, 10.x). We encourage _all users_ of Apollo Server to update to newer LTS versions of Node.js prior to the "end-of-life" dates for their current server version.

**We intend to drop support for Node.js 6.x in the next major version of Apollo Server.**

For more information, see [PR #2054](https://github.com/apollographql/apollo-server/pull/2054) and [our documentation](https://www.apollographql.com/docs/apollo-server/v2/migration-file-uploads.html).

### v2.2.7

- `apollo-engine-reporting`: When multiple instances of `apollo-engine-reporting` are loaded (an uncommon edge case), ensure that `encodedTraces` are handled only once rather than once per loaded instance. [PR #2040](https://github.com/apollographql/apollo-server/pull/2040)
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/apollo-cache-control/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-cache-control",
"version": "0.4.1",
"version": "0.5.0-alpha.3",
"description": "A GraphQL extension for cache control",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-datasource-rest/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-datasource-rest",
"version": "0.2.2",
"version": "0.3.0-alpha.3",
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-datasource/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-datasource",
"version": "0.2.2",
"version": "0.3.0-alpha.2",
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-engine-reporting/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-engine-reporting",
"version": "1.0.0",
"version": "1.0.0-alpha.3",
"description": "Send reports about your GraphQL services to Apollo Engine",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
3 changes: 1 addition & 2 deletions packages/apollo-graphql/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-graphql",
"version": "0.0.1-alpha.0",
"version": "0.0.1-alpha.1",
"description": "Apollo GraphQL utility library",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -13,7 +13,6 @@
"dependencies": {
"lodash.sortby": "^4.7.0"
},
"devDependencies": {},
"peerDependencies": {
"graphql": "^14.0.0"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-azure-functions/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-azure-functions",
"version": "2.3.3",
"version": "2.4.0-alpha.4",
"description": "Production-ready Node.js GraphQL server for Azure Functions",
"keywords": [
"GraphQL",
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-cache-memcached/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-cache-memcached",
"version": "0.2.2",
"version": "0.3.0-alpha.2",
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-cache-redis/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-cache-redis",
"version": "0.2.2",
"version": "0.3.0-alpha.2",
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-caching/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-caching",
"version": "0.2.2",
"version": "0.3.0-alpha.2",
"author": "opensource@apollographql.com",
"license": "MIT",
"repository": {
Expand Down
44 changes: 24 additions & 20 deletions packages/apollo-server-caching/src/InMemoryLRUCache.ts
Original file line number Diff line number Diff line change
@@ -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<V = string> implements KeyValueCache<V> {
private store: LRU.Cache<string, V>;

// 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 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
// 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;
}

// 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,
});
}

Expand All @@ -43,4 +44,7 @@ export class InMemoryLRUCache<V = string> implements KeyValueCache<V> {
async flush(): Promise<void> {
this.store.reset();
}
async getTotalSize() {
return this.store.length;
}
}
2 changes: 1 addition & 1 deletion packages/apollo-server-cloud-functions/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-cloud-functions",
"version": "2.3.3",
"version": "2.4.0-alpha.4",
"description": "Production-ready Node.js GraphQL server for Google Cloud Functions",
"keywords": [
"GraphQL",
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-cloudflare",
"version": "2.3.3",
"version": "2.4.0-alpha.4",
"description": "Production-ready Node.js GraphQL server for Cloudflare workers",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "apollo-server-core",
"version": "2.3.4",
"version": "2.4.0-alpha.4",
"description": "Core engine for Apollo GraphQL server",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
26 changes: 26 additions & 0 deletions packages/apollo-server-core/src/ApolloServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
GraphQLFieldResolver,
ValidationContext,
FieldDefinitionNode,
DocumentNode,
} from 'graphql';
import { GraphQLExtension } from 'graphql-extensions';
import { EngineReportingAgent } from 'apollo-engine-reporting';
Expand Down Expand Up @@ -92,6 +93,10 @@ function getEngineServiceId(engine: Config['engine']): string | undefined {
const forbidUploadsForTesting =
process && process.env.NODE_ENV === 'test' && !runtimeSupportsUploads;

function approximateObjectSize<T>(obj: T): number {
return Buffer.byteLength(JSON.stringify(obj), 'utf8');
}

export class ApolloServerBase {
public subscriptionsPath?: string;
public graphqlPath: string = '/graphql';
Expand All @@ -114,6 +119,11 @@ export class ApolloServerBase {
// the default version is specified in playground.ts
protected playgroundOptions?: PlaygroundRenderPageOptions;

// 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<DocumentNode>;

// 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.');
Expand All @@ -136,6 +146,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);
Expand Down Expand Up @@ -486,6 +499,18 @@ export class ApolloServerBase {
});
}

private initializeDocumentStore(): void {
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,
sizeCalculator: approximateObjectSize,
});
}

// This function is used by the integrations to generate the graphQLOptions
// from an object containing the request and other integration specific
// options
Expand All @@ -509,6 +534,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
Expand Down
Loading

0 comments on commit c5b71f8

Please sign in to comment.