Allow Asynchronous Execution And Fetching In GraphQL Java
See original GitHub issueCurrently, the GraphQL.execute(request)
method blocks until the result is ready, unlike graphql-js, which lets you handle the result in a callback.
Here, we propose an asynchronous rendition of graphql-java, which will allow you to not only execute a GraphQL request in a non-blocking manner, but also permit the data fetcher to wrap it’s results in a CompletableFuture.
Since our implementation relies on a Java 8 feature, it is being published as a separate project called graphql-java-async, so as to not impinge on graphql-java’s Java 6 compatibility requirements.
A non-blocking version of the famous “hello world” can be found in the README file. A more involved scenario involving publishing and subscribing to news articles can be seen in this groovy test case.
Is this something that could go as a “related project” under graphql-java?
-Karthick Sankarachary
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:13 (10 by maintainers)
I put up a PR to add the API interfaces that will allow a proper async implementation to be put in place.
The PR does NOT add an async implementation, but rather the API signature to allow it.
So I have been looking further into this and to me it seems that the current call pattern in ExecutionStrategy is incompatible with the reference implementation BUT does conform to spec
The spec says
http://facebook.github.io/graphql/#sec-Normal-and-Serial-Execution
So in this sense the current code allows for spec.
Today the execution in SimpleExecutionStrategy / ExecutionStrategy is depth first.
It calls execute() - with a list of fields resolveField() - for 1st field completeValue() - for that object execute() - if its an object type resolveField() - for 1st sub field completeValue() - stops at scalar
And so on in a depth first manner.
So given:
It will descend all of “gods” first right down to the sub objects before moving onto “wizards”.
But when writing an async implementation the current resolveField calling completeValue inside itself means you can do parallel operations easily.
The “fetch” inside resolveField is the part that is likely to take the most time and hence firing off multiple fetches at once is where the win is.
The reference implementation in JS does this.
However it waits for all asynch fetchs to complete together before moving onto the complete phase.
This then allows for libraries such as https://github.com/facebook/dataloader to “batch” together requests for similar objects.
But with the depth first approach we have today it means that we don get a “batch” of possible fields in order to 1) fire off at once and 2) use delayed “batching” to combine the requests.
I propose we change the structure of ExecutionStrategy so that
resolveField
does not callcompleteValue
.This will allow another async implementation to make breadth first data fetch requests (in parallel) and then complete them afterwards.
The alternative for another implementation is to “copy” all the code in resolveField and take out the complete call.
Another way would be to refactor it into
and then a new implementation can re-use the fetchField and completeField methods and not the resolveField (but rather write its own)
The reason I am really interested in this is to make async work better AND to make it possible for https://github.com/bbakerman/java-dataloader to work efficiently like in graphql-js