Skip to content

Commit d3811f2

Browse files
committed
threads blog
1 parent 4487653 commit d3811f2

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

content/blog/threads.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
+++
2+
title = "GraphQL Java and Threads"
3+
author = "Andreas Marek"
4+
tags = []
5+
categories = []
6+
date = 2021-02-05T00:00:00+10:00
7+
+++
8+
9+
# GraphQL Java and Threads
10+
11+
We follow a fundamental rule in GraphQL Java regarding Threads: GraphQL Java never creates
12+
Threads or interacts with Thread pools. We do this because we want to give the user the full control
13+
and whatever GraphQL Java would do it would not be correct in general.
14+
15+
Additionally to being strictly unopinionated regarding Threads GraphQL Java is also fully reactive,
16+
implemented via `CompletableFuture` (`CF`).
17+
These two constrain together mean we rely on the `CF` returned by the user.
18+
Specifically we piggyback on the `CF` returned by the `DataFetcher`
19+
(or other async methods which can be implemented by the user, but we focus here on `DataFetcher`
20+
as it is by far the most important).
21+
22+
23+
{{< highlight Java "linenos=table" >}}
24+
// Pseudo code in GraphQL Java
25+
26+
CompletableFuture<Object> dataFetcherResult = invokeDataFetcher();
27+
dataFetcherResult.thenApply(result -> {
28+
// in which Thread where this code happens is controlled by the CF returned
29+
continueExecutingQuery(result);
30+
});
31+
32+
{{< / highlight >}}
33+
<p/>
34+
35+
# Blocking DataFetcher
36+
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:
39+
40+
{{< highlight Java "linenos=table" >}}
41+
CompletableFuture<String> get(DataFetchingEnvironment env) {
42+
return dbAccess.supplyAsync( getValueFromDb(env), dbThreadPool );
43+
};
44+
{{< / highlight >}}
45+
<p/>
46+
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.
50+
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.
53+
For example for the following query:
54+
55+
{{< highlight Scala "linenos=table" >}}
56+
{
57+
field1
58+
field2
59+
field3
60+
}
61+
{{< / highlight >}}
62+
<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.
67+
68+
# In a fully reactive system
69+
If your system is fully reactive your `DataFetcher` will more look like this
70+
71+
{{< highlight Java "linenos=table" >}}
72+
CompletableFuture<String> get(DataFetchingEnvironment env) {
73+
return callAnotherServiceNonBlocking(env); // returns CompletableFuture
74+
};
75+
{{< / highlight >}}
76+
<p/>
77+
78+
The code above could be implemented via [Async Http Client](https://github.com/AsyncHttpClient/async-http-client)
79+
or [WebFlux WebClient](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client).
80+
Both provide fully reactive HTTP clients.
81+
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.
84+
85+
# Feedback or questions
86+
We use [GitHub discussions](https://github.com/graphql-java/graphql-java/discussions) for general feedback and questions.
87+
88+
You can also checkout our [Workshops](/workshops) for more possibilities to learn GraphQL Java.
89+
90+
91+
92+

0 commit comments

Comments
 (0)