question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow Asynchronous Execution And Fetching In GraphQL Java

See original GitHub issue

Currently, 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:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:13 (10 by maintainers)

github_iconTop GitHub Comments

3reactions
bbakermancommented, Apr 18, 2017

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.

2reactions
bbakermancommented, Jun 30, 2017

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

{
  birthday {
    month
  }
  address {
    street
  }
}

A valid GraphQL executor can resolve the four fields in whatever order it chose (however of course birthday must be resolved before month, and address before street).

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

   resolveField() - for 2nd field
        completeValue() - for that object
            execute() - if its an object type
               resolveField() - for 2nd sub field
                   completeValue() - stops at scalar

And so on in a depth first manner.

So given:

{
  gods {
    name
    invitedBy {
      name
    }
  }
  wizards {
    name
    invitedBy {
      name
    }
  }
}

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 call completeValue.

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

 resolveField
     fetchField
     completeField

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

Execution - GraphQL Java
You can make execution of the DataFetcher asynchronous by returning a CompletionStage to data, ... Remember graphql allows partial results with errors.
Read more >
Synchronous and Asynchronous Version of GraphQL Client in ...
Hi @Benoit_Lubek , No i am not working on an Android Project, I have an internal application in Java which will be using...
Read more >
How to get your GraphQL Java server up and running in no time
Each query execution is Asynchronous in graphql-java. When you call build.execute(executionInput), it returns a CompletableFuture object which ...
Read more >
Does the GraphQL#execute run all DataFetchers on the same ...
Yes. Based on what I see from the source codes , if all data fetchers only return POJO, the whole execution will execute...
Read more >
Execution - GraphQL
After being validated, a GraphQL query is executed by a GraphQL server which returns a result that mirrors the shape of the requested...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found