We follow a fundamental rule in GraphQL Java regarding Threads: GraphQL Java never creates Threads or interacts with Thread pools. We do this because we want to give the user the full control and whatever GraphQL Java would do, it would not be correct for every use case.
Additionally to being strictly unopinionated regarding Threads, GraphQL Java is also fully reactive,
These two constrain together mean we rely on the
CF returned by the user.
Specifically we piggyback on the
CF returned by the
(or other async methods which can be implemented by the user, but we focus here on
as it is by far the most important).
Lets assume you are accessing a DB in a blocking way in your
This is not completely wrong, but not recommend in general as the consequence of this kind of
is that GraphQL can’t execute the query in the most efficient way.
For example for the following query:
DataFetcher for these
dbData fields don’t return a
but block the Thread until the data is read, GraphQL Java will not work with maximum efficiency.
GraphQL Java can invoke the
DataFetcher for all three fields in parallel. But if your
dbData1 is blocking, GraphQL Java will also be blocked and only invoke the next
The recommend solution to this problem is offloading your blocking code onto a separate Thread pool
as shown here:
The subsequent work done by GraphQL Java will be executed in the same
dbThreadPool until it
encounters a new
DataFetcher returned by the user code and this new
CF dedicates the Thread
for the subsequent work.
If you want to have separate pools for different kind of work, one for the actual
DataFetcher which normally
involve IO and one of the actual GraphQL Java work (which is pure CPU), you need to switch back from your offloaded
pool to a dedicated GraphQL Java pool before returning the
CF. You can achieve this with code like this:
.handleAsync which doesn’t do anything except forwarding the result, but on a
different pool (
This way you have different pools for different kind of work (one for CPU bound GraphQL Java work and one for multiple ones for IO bound work), which can be configured and monitored independently.
If your system is fully reactive your
DataFetcher will more look like this
Because the code is non blocking there is no need to offload anything on a dedicated Thread pool to avoid blocking GraphQL Java.
You still might want to consider using a dedicated GraphQL Java pool as you otherwise would use Threads which are dedicated to IO. How much this is really relevant depends highly on your use case.
Async Http Client (
AHC) uses by default 2 * #cores (this value comes actually from Netty) Threads. If you
don’t use a dedicated Thread Pool for GraphQL Java you might encounter situations under load where all
Threads are either busy or blocked by GraphQL Java code and as a result your system is not as performant as it
could be. Normally only load tests in production like environments can show the relevance of different Thread pools.
We use GitHub Discussions for general feedback and questions.