Skip to content

Commit

Permalink
Allow the APQ cache to be configured with a different TTL value.
Browse files Browse the repository at this point in the history
Previously, there was no way to specify this value using any of our
`KeyValueCache` implementations - whether Memcached, Redis, or otherwise.

This provides that ability by setting a `ttlSeconds` to a numeric or `null`
(to specify no TTL).
  • Loading branch information
abernix committed Dec 19, 2019
1 parent 83a8400 commit d025580
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 3 deletions.
8 changes: 8 additions & 0 deletions packages/apollo-server-core/src/graphqlOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ export type DataSources<TContext> = {

export interface PersistedQueryOptions {
cache: KeyValueCache;
/**
* Specified in **seconds**, this time-to-live (TTL) value limits the lifespan
* of how long the persisted query should be cached. To specify a desired
* lifespan of "infinite", set this to `null`, in which case the eviction will
* be determined by the cache's eviction policy, but the record will never
* simply expire.
*/
ttlSeconds?: number | null;
}

export default GraphQLServerOptions;
Expand Down
15 changes: 12 additions & 3 deletions packages/apollo-server-core/src/requestPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,18 @@ export async function processGraphQLRequest<TContext>(
// an error) and not actually write, we'll write to the cache if it was
// determined earlier in the request pipeline that we should do so.
if (metrics.persistedQueryRegister && persistedQueryCache) {
Promise.resolve(persistedQueryCache.set(queryHash, query)).catch(
console.warn,
);
Promise.resolve(
persistedQueryCache.set(
queryHash,
query,
config.persistedQueries &&
typeof config.persistedQueries.ttlSeconds !== 'undefined'
? {
ttl: config.persistedQueries.ttlSeconds,
}
: Object.create(null),
),
).catch(console.warn);
}

let response: GraphQLResponse | null = await dispatcher.invokeHooksUntilNonNull(
Expand Down
57 changes: 57 additions & 0 deletions packages/apollo-server-integration-testsuite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,63 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
});
});

it('when ttlSeconds is set, passes ttl to the apq cache set call', async () => {
const cache = createMockCache();
app = await createApp({
graphqlOptions: {
schema,
persistedQueries: {
cache: cache,
ttlSeconds: 900,
},
},
});

await request(app)
.post('/graphql')
.send({
extensions,
query,
});

expect(cache.set).toHaveBeenCalledWith(
expect.stringMatching(/^apq:/),
'{testString}',
expect.objectContaining({
ttl: 900,
}),
);
});

it('when ttlSeconds is unset, ttl is not passed to apq cache',
async () => {
const cache = createMockCache();
app = await createApp({
graphqlOptions: {
schema,
persistedQueries: {
cache: cache,
},
},
});

await request(app)
.post('/graphql')
.send({
extensions,
query,
});

expect(cache.set).toHaveBeenCalledWith(
expect.stringMatching(/^apq:/),
'{testString}',
expect.not.objectContaining({
ttl: 900,
}),
);
}
);

it('errors when version is not specified', async () => {
const result = await request(app)
.get('/graphql')
Expand Down

0 comments on commit d025580

Please sign in to comment.