-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disable cache in ApolloServer when using RESTDataSource #1562
Disable cache in ApolloServer when using RESTDataSource #1562
Comments
RESTDatasource will by default cache API responses based on their public getUser() {
// This overrides that behavior and caches user responses for 60 seconds
// See https://github.com/apollographql/apollo-server/issues/1460
this.get('/v1/user', null, { cacheOptions: { ttl: 60 } })
} Hope this helps! |
@timkendall thanks for your reply... The above |
It's up to you. Again ideally the REST API that you're hitting would respond with correct |
@timkendall I tried both setting ttl:0, ttl:1 and setting cache-control to "no-cache, no-store, must-revalidate" but it caches anyway indefinately (until server is restarted) |
I have this same issue. I have enabled memcached for my datasource queries. Running the query a second time does not even try to query memcached. tested using nettop to see network connections. casuing major issues with application. LRU cache should be flushed after request is fulfilled, or not used if another cache is enabled. Edit: after doing some debugging, RESTDataSource uses memoizedResults (in-memory Map caching) and prioritizes that over anything else. It does not ever delete this cache, so will never clear that memory. I am working to see if I can add code so that at the end of a request, this is destroyed. |
@timkendall @martijnwalraven @lmx2k5
and i am using the formatResponse for the server to loop through all of my datasources and calling that function. This way I know my GQL query is complete and memory is cleared before the next query is processed. if anyone has a better solution, i am all game for it. |
@dragonfriend0013 How are you configuring your data sources? They have been designed to be initialized per request, which is why |
@martijnwalraven |
@martijnwalraven |
I tried this approach for the time being. but it is a hacky-wacky way to do it.. |
We have a data source that should't cache the results and we solved by: import { HTTPCache, RESTDataSource } from 'apollo-datasource-rest'
export default class NoCacheDataSource extends RESTDataSource {
constructor() {
super()
this.baseURL = someHost
}
initialize({ context }) {
this.context = context
this.httpCache = new HTTPCache()
}
} Every call instantiates a |
ApolloServer I assumed that not setting it would not add any caching to my API I also confirm that setting
Unfortunately, manipulating the response here to remove |
Okay I found a way to completely disable the apollo-rest-datasource cache:
this will create a unique cache key for each request. Ugly hack as that data will still be in memory so be careful if you use it |
Hi all The reason is that there are simple var checks on truthiness, for example
and here
The fix should be checking let ttl = ttlOverride !== undefined ? ttlOverride : Math.round(policy.timeToLive() / 1000); (ttlOverride !== undefined && policy.age() < ttlOverride) I'm happy to open PR if that's the real case |
@Grimones ttl: -1 is not working either, you can tell by defining your cache options like this:
put a breakpoint or console.log in the callback, whenever it triggers it means Apollo made a request instead of getting the data from the cache The problem seems to be in RESTDataSource.ts: the Promise from |
@DanielHoffmann but isn't it the idea of Regarding Oh, I think I get your point. Maybe there is a point to add the ttl value to cache key? edit |
@DanielHoffmann I have the same issue and I suspect it comes from using the graphql-modules setup with RESTDataSource (like in the following example: https://graphql-modules.com/docs/guides/data-sources). It likely doesn't configure it properly as suggested by @martijnwalraven in the above comment, but I have to investigate further. Even though according to my rest api response headers, my call should not be cached, the memoized response is returned in subsequent GraphQL requests and Caching and memoization could maybe be documented a bit clearer for RESTDataSource as there is (almost) no mention of how it works. If I understand correctly:
|
@Grimones the memoization happening in RESTDataSource is not taking into account the ttl, that is why the responses are always cached forever. From what I can tell in the code RESTDataSource.ts is supposed to be stateless and HTTPCache is supposed to have all the state/caching Checking the commit history it seems @martijnwalraven was the one who added the memoization to that file. Could you maybe take a look into this issue? The memoization seems to be holding old responses in memory and returning them instead of checking if they are in the cache |
@DanielHoffmann While How are you instantiating
|
@martijnwalraven ugh, you are right, I had a single instance for my data source instead of one per request. Now I understand why you have memoization there (so multiple identical requests fired from the same API call are not repeated). Thanks for the tip! This is quite an easy error to run into, maybe add some warnings about it? Compare the data sources instances to the previous request data sources instances. I suspect the other people here are running into the same error |
Also I think it's worth to make a note that you should use function instead of object when passing data sources And again problem with ttl = 0 still persist I think I'll open a PR when will have free time checking ttl against undefined |
What if cacheOptions.ttl, dont do anything? |
In my case, the issue was not the cache of the RESTDataSource class but a wrong initialization of the export async function getApolloServer() {
const schema = await buildSchema()
const dataSources = await getDataSources()
const apolloServer = new ApolloServer({
schema,
dataSources: () => dataSources,
... This was wrong because the The solution for me was to initialize a new dataSources like written inside the doc dataSources: () => {
return {
moviesAPI: new MoviesAPI(),
personalizationAPI: new PersonalizationAPI(),
};
}, Hope this will help someone :) |
Closing this because the issue seems to be resolved. |
async properties of |
I needed a way to programmatically clear the default built-in cache, and was able to with:
|
@MakhBeth Yes. Thanks. I have the same issue as you. |
@timkendall #1562 (comment) Is it true that I would rather have a single RESTDataSource instance for all the requests in my server in order to reduce GC pressure, leverage caching between requests, etc. It seems to me that this caching issue is the only thing preventing me from using it that way. |
@RobertFischer, as you can see here it defers to the http-cache-semantics library. I wrote some unit tests around 'apollo-server' and was able to confirm that it respected both What I did discover is that it doesn't fully support the |
I was forced to do this as well.
|
Generell Solution for @nharlow89 answer: class NoCacheSource extends RESTDataSource {
didReceiveResponse(response: Response, request: Request) {
this.memoizedResults.delete(this.cacheKeyFor(request));
return super.didReceiveResponse(response, request);
}
} But still pain in the ass. |
It's important to remove the cache for error responses as well, otherwise you will experience unexpected results. class NoCacheSource extends RESTDataSource {
deleteCacheForRequest(request: Request) {
this.memoizedResults.delete(this.cacheKeyFor(request));
}
didReceiveResponse(response: Response, request: Request) {
this.deleteCacheForRequest(request);
return super.didReceiveResponse(response, request);
}
didEncounterError(error: Error, request: Request) {
this.deleteCacheForRequest(request);
return super.didEncounterError(error, request);
}
} |
this worked for me! |
I am using RESTDataSource to fetch data from REST api's but data is being cached.
How to disable cache since data keeps changing in thequery resolver.
Below is the node.js code.
The text was updated successfully, but these errors were encountered: