-
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
Undocumented and non-configurable memoization feature on apollo-datasource-rest #6603
Undocumented and non-configurable memoization feature on apollo-datasource-rest #6603
Comments
Thanks for debugging and finding the issue @Jaxolotl! I have shared with the Apollo Server team too, but I will share my ideas of how we could solve this with a new minor release. Let me know what you think Create a new config/class propertyFor backwards compatibility, we could add a new property called if (request.method === 'GET' && cacheGetRequests !== false) {
let promise = this.memoizedResults.get(cacheKey);
// ....
} This will hopefully work still even if some one has created their own implementation of That means then to disable memoized results you could do this in the constructor. class PersonalizationAPI extends RESTDataSource {
constructor() {
super();
this.cacheGetRequests = false;
}
} Add another hook pointToday we have a few hook points: protected shouldCacheRequest(request: RequestOptions): boolean {
return request.method === 'GET';
}
//....
if (shouldCacheRequest()) {
let promise = this.memoizedResults.get(cacheKey);
// ....
} |
Hi @smyrick thank you for the quick reply! for the hook points:I'm not really sure how opening the cache implementation for extension/overriding would impact on the project. Personally I wouldn't go in that direction and cannot imagine a scenario where caching a non query verbs ( command-like verb like PUT, POST, DELETE) would benefit from caching for the config value:That sounds less intrusive, although I'd suggest something like this:
That way we do an earlier return with a simpler condition easy to test and avoiding dealing with the if/else statements. If we add it to the extra thoughtsI think the feature has a very valid purpose and it would be great to have a better control over it. Switching it on and off might not be a good approach, what if we add a time value, e.g. if 2 GET requests with the same signature have less than 500ms difference then return the memoized promise, otherwise make the request and update the memoized entry, that way you can switched on/off AND you can switched on and define a max life span.
Any thoughts? |
I like the idea of adding more control to the caching features but I also want to make sure we don't change the existing behavior of the library. Even if we agree it needs to be updated, having the results potential flushed from the cache would be a breaking change in logic (and require a major version) and someone today might be using this as is. I totally missed this before but there already is an open in the cache set to pass in a Default // Class props
this.cacheEnabled = true;
this.cacheTTL = null;
// Logic
if (this.cacheEnabled) {
let promise = this.memoizedResults.get(cacheKey);
if (promise) return promise;
if (request.method === 'GET') {
promise = performRequest();
this.memoizedResults.set(cacheKey, promise, { ttl: cacheTTL });
return promise;
} else {
this.memoizedResults.delete(cacheKey);
return performRequest();
}
} else {
return performRequest();
} |
By default, RESTDataSource caches all outgoing GET requests in a separate memoized cache from the regular response cache. It makes the assumption that all responses from HTTP GET calls are cacheable by their URL. If a request is made with the same cache key (URL by default) but with an HTTP method other than GET, the cached request is then cleared. This change adds a new class property requestCacheEnabled (which defaults to true to match current behavior) which allows users to disable the cache. You might want to do this if your API is not actually cacheable or your data changes over time. Separately it documents this feature exists and adds more info about how to set a TTL for the entire HTTP cache. Fixes #6603
@Jaxolotl This is now released in apollo-datasource-rest 3.7 |
Package name and version
apollo-datasource-rest V3.6.1
Expected behavior
Actual behavior
Description of the case
The datasource will keep a memoized version of all the GET requests until a POST request is made using the same URI or you programmatically delete the entry key (
this.memoizedResults.delete(<MY_KEY>)
) or clear all the entries (this.memoizedResults.clear()
).Not being documented and not having and opt-out configuration for the feature will cause a data inconsistency problem whenever you only make get requests to a system you have just read-only access (if another system updates the data you will never get the new data)
temporary workaround
You can always do the following to workaround the problem on your datasource derived class but is not a solution
Steps to repro
The package code is simple enough and self explanatory to be able to repro with a unit test.
Extra notes
I saw a couple tickets that might be related to this problem but they were described as generic caching issues without providing a detailed explanation of the problem. Hope you find it useful
apollographql/datasource-rest#72
apollographql/datasource-rest#46
The text was updated successfully, but these errors were encountered: