@@ -34,36 +34,72 @@ as it is by far the most important).
3434
3535# Blocking DataFetcher
3636
37- So for example lets assume your ` DataFetcher ` access a DB (blocking, not reactive) and you decide
38- to offload this work to a dedicated Thread pool:
37+ Lets assume your accessing a DB in blocking way in your ` DataFetcher ` :
3938
4039{{< highlight Java "linenos=table" >}}
41- CompletableFuture< String > get(DataFetchingEnvironment env) {
42- return dbAccess.supplyAsync( getValueFromDb(env), dbThreadPool );
40+ String get(DataFetchingEnvironment env) {
41+ return getValueFromDb(env); // blocking the Thread until the value is read from DB
4342 };
4443{{< / highlight >}}
4544<p />
4645
47- The subsequent work done by GraphQL Java will be executed in the same ` dbThreadPool ` until it
48- encounters a new ` DataFetcher ` returned by the user code and this new ` CF ` dedicates the Thread
49- for the subsequent work.
46+ This is not completely wrong, but not recommend in general as the consequence of this kind of ` DataFecher `
47+ is that GraphQL can't execute the query in the most efficient way.
5048
51- In general offloading your work to a dedicated Thread pool is recommend if your ` DataFetcher ` is blocking,
52- because otherwise GraphQL will not execute with maximal efficiency.
5349For example for the following query:
5450
5551{{< highlight Scala "linenos=table" >}}
5652{
57- field1
58- field2
59- field3
53+ dbData1
54+ dbData2
55+ dbData3
6056}
6157{{< / highlight >}}
6258<p />
63-
64- GraphQL can invoke the ` DataFetcher ` for all three fields in parallel. But if your ` DataFetcher ` for
65- ` field1 ` is blocking GraphQL Java will also be blocked and only invoke the next ` DataFetcher ` once ` field `
66- is finished. Offloading your blocking code onto a separate Thread pool a shown above solves this problem.
59+
60+ If the ` DataFetcher ` for these ` dbData ` fields don't return a ` CF ` ,
61+ but block the Thread until the data is read, GraphQL Java will not work with maximum efficiency.
62+
63+ GraphQL Java can invoke the ` DataFetcher ` for all three fields in parallel. But if your ` DataFetcher ` for
64+ ` dbData1 ` is blocking GraphQL Java will also be blocked and only invoke the next ` DataFetcher ` once ` dbData1 `
65+ is finished.
66+ The recommend solution to this problem is offloading your blocking code onto a separate Thread pool
67+ as shown here:
68+
69+ {{< highlight Java "linenos=table" >}}
70+ CompletableFuture<String > get(DataFetchingEnvironment env) {
71+ return CompletableFuture.supplyAsync( getValueFromDb(env), dbThreadPool );
72+ };
73+ {{< / highlight >}}
74+ <p />
75+ This code will maximize the performance and will cause all three fields to be fetched in parallel.
76+
77+ # Different pools for different work
78+
79+ The subsequent work done by GraphQL Java will be executed in the same ` dbThreadPool ` until it
80+ encounters a new ` DataFetcher ` returned by the user code and this new ` CF ` dedicates the Thread
81+ for the subsequent work.
82+
83+ If you want to have separate pools for different kind of work, one for the actual ` DataFetcher ` which normally
84+ involve IO and one of the actual GraphQL Java work (which is pure CPU), you need to switch back from your offloaded
85+ pool to a dedicated GraphQL Java pool before returning the ` CF ` . You can achieve this with code like this:
86+
87+ {{< highlight Java "linenos=table" >}}
88+ CompletableFuture<String > get(DataFetchingEnvironment env) {
89+ return CompletableFuture.supplyAsync( getValueFromDb(env), dbThreadPool )
90+ .handleAsync((result,exception) -> {
91+ if(exception !=null) throw exception;
92+ return result;
93+ }, graphqlJavaPool);
94+ };
95+ {{< / highlight >}}
96+ <p />
97+
98+ Notice the ` .handleAsync ` which doesn't do anything except forwarding the result, but on a
99+ different pool (` graphqlJavaPool ` ).
100+
101+ This way you have different pools for different kind of work (one for CPU bound GraphQL Java work and one
102+ for multiple ones for IO bound work), which can be configured and monitored indepently.
67103
68104# In a fully reactive system
69105If your system is fully reactive your ` DataFetcher ` will more look like this
@@ -79,8 +115,11 @@ The code above could be implemented via [Async Http Client](https://github.com/A
79115or [ WebFlux WebClient] ( https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client ) .
80116Both provide fully reactive HTTP clients.
81117
82- Because the code is non blocking there is no need to offload anything on a dedicated Thread pool and
83- GraphQL Java "automatically" works as efficiently as possible.
118+ Because the code is non blocking there is no need to offload anything on a dedicated Thread pool to avoid blocking
119+ GraphQL Java.
120+
121+ But you still might want to consider using a dedicated GraphQL Java pool as you otherwise use
122+ threads which are dedicated to IO.
84123
85124# Feedback or questions
86125We use [ GitHub Discussions] ( https://github.com/graphql-java/graphql-java/discussions ) for general feedback and questions.
0 commit comments