close
The Wayback Machine - https://web.archive.org/web/20201108004530/https://github.com/graphql-java/java-dataloader/pull/65
Skip to content
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

[WIP] Proposal: Handle futureCache.get exceptions #65

Open
wants to merge 1 commit into
base: master
from

Conversation

@rharriso
Copy link

@rharriso rharriso commented Apr 9, 2020

I'd like to propose that the DataLoaderHelper handle situations where cacheMap.get completes exceptionally. Currently this class assumes that if the cache contains a key, then the value associated with that key is the appropriate type.

Note these changes have not been tested

Sorry if my use of CompletableFuture is crude, I'd appreciate any composition advice.

Motivation

I'm planning on using Redis as an expiring cache. The data has to be serialized and de-serialized on read and write. This cache is an external service and is shared between graphql server instances. Problems with network activity and differing application versions could cause issues with smooth serde.

Changes

The new flow for load is as follows.

  1. Try to load from cache:
    a. Returns Optional.empty if: cache disabled, key not in cache, Cache.get fails or returns null
    b. Returns Optional<v> otherwise
  2. If cache load is present, return result
  3. If cache load not present, load from source
  4. If caching enabled, store loadedValue in cache
  5. Result is supplied by completable future.
return CompletableFuture.completedFuture(Optional.empty());
}

return futureCache.get(key).handleAsync((v, exception) -> {

This comment has been minimized.

@bbakerman

bbakerman Apr 15, 2020
Member

handleAsync use the standard ForkJoin pool - we make it a policy to never introduce threading into the library. Only the consuming code of this lib can really know what threading strategy to use.

If we accepted this change, this would have to be the version that takes and executor and it would have to come from DataLoaderOptions say

if (futureCache.containsKey(cacheKey)) {
stats.incrementCacheHitCount();
return futureCache.get(cacheKey);
return loadFromCache(key).thenApplyAsync((cachedValue) -> {

This comment has been minimized.

@bbakerman

bbakerman Apr 15, 2020
Member

Same problem : thenApplyAsync uses the standard FookJoinPoll - see above

var sourceResult = loadFromSource(key, loadContext);
sourceResult.thenAcceptAsync((sourceValue) -> {
if (cachingEnabled) {
futureCache.set(cacheKey, java.util.concurrent.CompletableFuture.supplyAsync(() -> sourceValue));

This comment has been minimized.

@bbakerman

bbakerman Apr 15, 2020
Member

There would be no need for

java.util.concurrent.CompletableFuture.supplyAsync(() -> sourceValue)

if you have a value then you can just do CompleteableFuture.completedValue(v)

That is a CF thats is finished successfully with value v

return sourceResult.get();
} catch (InterruptedException | java.util.concurrent.ExecutionException e) {
return null;
}

This comment has been minimized.

@bbakerman

bbakerman Apr 16, 2020
Member

This is a blocking call - sourceResult.get();

DataLoader MUST always be async - ALWAYS. We cant have this.

@rharriso
Copy link
Author

@rharriso rharriso commented Apr 16, 2020

@bbakerman thanks for the feedback. I'll see if I can resolve these problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants
You can’t perform that action at this time.