Apollo-server: RESTDataSource has double caching

Created on 9 Aug 2018  路  10Comments  路  Source: apollographql/apollo-server


It stores all caches in cache implementation InMemory, Redis, Memcache and also in Map object. Second time if you send same request it will return the cache value from the Map. This will override ttl config. Not sure also how this is safe, in terms of memory, how big the map object will be if it stores all responses.

Most helpful comment

@uarsovic Yeah, that's not how data sources are meant to be used. You should export the class from your other module and instantiate it in the dataSources function.

Sharing a data source between requests will be guaranteed to lead to trouble, because it means you don't have access to the current request's context through this.context for example. And we plan on extending data sources with more features that require them to be bound to a request, like tracing of backend calls.

All 10 comments

This is by design. Data sources are instantiated per request, so the internal map is meant as a short lived memoization cache that avoids duplicate backend fetches. The actual cache is shared and long-lived, so that's where the TTL is respected.

@martijnwalraven I have example where I extend RESTDataSource and we use get for fetching the data from 3rd party. When we get different response data it is always cached in "memoizedResults" and that map will be evergrowing. Or am I missing something? is that map ever going to be freed?

@uarsovic Because data sources are instantiated per request, memoizedResults won't live beyond the duration of the current request.

@martijnwalraven In my case, my map has e.g. three elements in it. And i can continue to grow it easily.

@uarsovic Could you elaborate on what you mean here? The map is only kept for the duration of a single GraphQL request, so I don't see the issue.

@martijnwalraven I have done three graphQL POST requests with three different id values. And had only one instance of RESTDataSource and map had three different values in it. And if I continue to make more graphQL POST requests with different id's it will continue to grow.
One more question. Where is datasource instantiated? Somewhere internally? Since i pass instance in the configuration of the ApolloServer

@uarsovic You pass a function that instantiates your data sources to the ApolloServer constructor under a dataSources key, and the server will call that function for every request and configure the data source so it has access to the context and cache. See the example in the docs.

Is that not what you were doing?

@martijnwalraven In index.js I have:

  • const myService = require('./MyServiceRedis');
  • dataSources: () => { return { myService: myService }; }

In my service I have:

  • class MyServiceRedis extends RESTDataSource
  • methods calling this.get
  • module.exports = new MyServiceRedis();

@uarsovic Yeah, that's not how data sources are meant to be used. You should export the class from your other module and instantiate it in the dataSources function.

Sharing a data source between requests will be guaranteed to lead to trouble, because it means you don't have access to the current request's context through this.context for example. And we plan on extending data sources with more features that require them to be bound to a request, like tracing of backend calls.

I think this should be somehow documented, I had the same problem.

Was this page helpful?
0 / 5 - 0 ratings