1
1
package graphql .execution ;
2
2
3
3
import java .util .ArrayList ;
4
- import java .util .Arrays ;
5
4
import java .util .LinkedHashMap ;
6
5
import java .util .List ;
7
6
import java .util .Map ;
11
10
import java .util .concurrent .ForkJoinPool ;
12
11
import java .util .function .Function ;
13
12
import java .util .stream .Collectors ;
14
- import java .util .stream .Stream ;
15
13
16
14
import graphql .ExceptionWhileDataFetching ;
17
15
import graphql .ExecutionResult ;
21
19
import graphql .schema .GraphQLObjectType ;
22
20
import graphql .schema .GraphQLType ;
23
21
24
- import static graphql .async .ExecutionFuture .completable ;
25
22
import static graphql .async .ExecutionFuture .array ;
23
+ import static graphql .async .ExecutionFuture .completable ;
26
24
27
25
/**
28
26
* <p>AsyncExecutionStrategy implements the {@link ExecutionStrategy} in a non-blocking manner.</p>
42
40
*/
43
41
public class AsyncExecutionStrategy extends ExecutionStrategy {
44
42
45
- protected ExecutorService executorService ;
46
43
protected boolean serial ;
44
+ protected ExecutorService executorService ;
47
45
48
46
public static AsyncExecutionStrategy serial () {
49
47
return new AsyncExecutionStrategy (true );
@@ -70,6 +68,10 @@ protected AsyncExecutionStrategy(boolean serial, ExecutorService executorService
70
68
this .executorService = executorService ;
71
69
}
72
70
71
+ public boolean isSerial () {
72
+ return serial ;
73
+ }
74
+
73
75
/**
74
76
* Resolve the given fields in parallel and return an execution result without blocking.
75
77
*
@@ -87,17 +89,32 @@ public ExecutionResult execute(final ExecutionContext executionContext,
87
89
Set <String > fieldNames = fields .keySet ();
88
90
89
91
// Create tasks to resolve each of the fields
90
- (serial ? fieldNames .stream () : fieldNames .parallelStream ()).forEach ((fieldName ) -> {
91
- fieldFutures .put (fieldName , CompletableFuture .supplyAsync (
92
- () -> resolveField (executionContext , parentType , source , fields .get (fieldName )),
93
- executorService ));
94
- });
92
+ CompletableFuture <ExecutionResult > previousField = CompletableFuture .completedFuture (null );
93
+ for (String fieldName : fieldNames ) {
94
+ CompletableFuture <ExecutionResult > fieldFuture ;
95
+ if (serial ) {
96
+ // Block the current field until the previous field is done
97
+ fieldFuture = previousField .thenCompose (result -> CompletableFuture .supplyAsync (
98
+ () -> resolveField (executionContext , parentType , source , fields .get (fieldName )),
99
+ executorService
100
+ ));
101
+ previousField = fieldFuture ;
102
+ } else {
103
+ // Resolve every field in parallel, independent of each other
104
+ fieldFuture = CompletableFuture .supplyAsync (
105
+ () -> resolveField (executionContext , parentType , source , fields .get (fieldName )),
106
+ executorService
107
+ );
108
+ }
109
+ fieldFutures .put (fieldName , fieldFuture );
110
+ }
111
+
95
112
96
113
// Prepare a completable for the map of field results
97
114
CompletableFuture <Map <String , Object >> resultsFuture = CompletableFuture
98
115
// First, wait for all the tasks above to complete
99
116
.allOf (array (fieldFutures .values ()))
100
- .exceptionally (( throwable ) -> {
117
+ .exceptionally (throwable -> {
101
118
executionContext .addError (new ExceptionWhileDataFetching (throwable ));
102
119
return null ;
103
120
})
@@ -107,25 +124,25 @@ public ExecutionResult execute(final ExecutionContext executionContext,
107
124
return CompletableFuture
108
125
.allOf (array (
109
126
fieldNames .stream ()
110
- .map (( fieldName ) -> {
127
+ .map (fieldName -> {
111
128
final ExecutionResult fieldResult = fieldFutures .get (fieldName ).join ();
112
129
fieldResults .put (fieldName , fieldResult );
113
130
return completable (fieldResult , executorService );
114
131
})
115
132
.collect (Collectors .<CompletableFuture <ExecutionResult >>toList ())
116
133
))
117
- .exceptionally (( throwable ) -> {
134
+ .exceptionally (throwable -> {
118
135
executionContext .addError (new ExceptionWhileDataFetching (throwable ));
119
136
return null ;
120
137
})
121
- .thenApplyAsync (( resultsDone ) -> fieldResults , executorService );
138
+ .thenApplyAsync (resultsDone -> fieldResults , executorService );
122
139
}, executorService )
123
140
// Last, collect the results of the field into a map
124
- .exceptionally (( throwable ) -> {
141
+ .exceptionally (throwable -> {
125
142
executionContext .addError (new ExceptionWhileDataFetching (throwable ));
126
143
return new LinkedHashMap <>();
127
144
})
128
- .thenApplyAsync (( fieldResults ) -> {
145
+ .thenApplyAsync (fieldResults -> {
129
146
Map <String , Object > results = new LinkedHashMap <>();
130
147
for (String fieldName : fieldResults .keySet ()) {
131
148
ExecutionResult fieldResult = fieldResults .get (fieldName );
@@ -155,10 +172,10 @@ protected ExecutionResult completeValue(final ExecutionContext executionContext,
155
172
return ((CompletableFuture <ExecutionResult >) result )
156
173
.thenComposeAsync (
157
174
(Function <Object , CompletableFuture <ExecutionResult >>)
158
- ( completedResult ) -> completable (
175
+ completedResult -> completable (
159
176
executionStrategy .completeValue (executionContext , fieldType , fields , completedResult ),
160
177
executorService ), executorService )
161
- .exceptionally (( throwable ) -> {
178
+ .exceptionally (throwable -> {
162
179
executionContext .addError (new ExceptionWhileDataFetching (throwable ));
163
180
return null ;
164
181
})
@@ -180,7 +197,7 @@ protected ExecutionResult completeValueForList(ExecutionContext executionContext
180
197
super .completeValueForList (executionContext , fieldType , fields , result );
181
198
List <Object > completableResults = (List <Object >) executionResult .getData ();
182
199
List <Object > completedResults = new ArrayList <>();
183
- completableResults .forEach (( completedResult ) -> {
200
+ completableResults .forEach (completedResult -> {
184
201
completedResults .add ((completedResult instanceof CompletableFuture ) ?
185
202
((CompletableFuture ) completedResult ).join () : completedResult );
186
203
});
0 commit comments