graphql-java-kickstart/graphql-java-servlet

Implement complete Async request execution flow

artem-ag opened this issue · 1 comments

Is your feature request related to a problem? Please describe.
AbstractGraphQLHttpServlet implements async request execution by deferring execution to user provided ExecutorService. This still means that a new thread is held per request being executed. Complete async support would allow to avoid holding any threads while service is waiting for any downstream IO to complete increasing GraphQL server scalability.

Describe the solution you'd like
GraphQLInvoker already supports async execution by returning CompletableFuture.
To solve this several classes need to be converted to run execution asynchronously and call Jetty asyncContext.complete() after last of CompletableFuture is complete.
These include:

  1. GraphQLInvoker.query() to become async and return CompletableFuture.
  2. HttpRequestHandlerImpl invoke() and execute() methods to become async and return CompletableFuture. handle() method either to become async, or accept Jetty AsyncContext to call asyncContext.complete() upon execute() completion.
  3. AbstractGraphQLHttpServlet.doRequest() will need to change the way callback are processed after other methods will be converted to Async.

Describe alternatives you've considered
Alternative is to not use Async execution at all, to reduce overhead of transferring "work" from Jetty thread pool to asyncExecutor thread pool and increasing Jetty thread pool size instead. Number of parallel requests that can be processed is limited by the size of Jetty thread pool. In async mode number of parallel requests is limited by the size of GraphQLConfiguration.asyncExecutor. That's practically the same as limiting at Jetty level, except additional "work" is required to move request execution from Jetty thread pool to GraphQLConfiguration one.

Additional context
N/A

+1, I'm in a situation where I'm fetching data from an async backend, so that would be really useful.

In async mode number of parallel requests is limited by the size of GraphQLConfiguration.asyncExecutor. That's practically the same as limiting at Jetty level, except additional "work" is required to move request execution from Jetty thread pool to GraphQLConfiguration one.

Completely agree with that.