22
33import graphql .ExecutionResult ;
44import graphql .ExecutionResultImpl ;
5+ import graphql .kickstart .execution .FutureExecutionResult ;
56import graphql .kickstart .execution .GraphQLInvoker ;
67import graphql .kickstart .execution .GraphQLQueryResult ;
78import graphql .kickstart .execution .error .GenericGraphQLError ;
1314import java .io .IOException ;
1415import java .io .UncheckedIOException ;
1516import java .util .Optional ;
17+ import java .util .concurrent .CancellationException ;
1618import java .util .concurrent .CompletableFuture ;
1719import java .util .concurrent .CompletionException ;
1820import java .util .concurrent .atomic .AtomicReference ;
@@ -40,7 +42,7 @@ public void execute(
4042 if (request .isAsyncSupported ()) {
4143 invokeAndHandleAsync (invocationInput , request , response , listenerHandler );
4244 } else {
43- invokeAndHandle ( invocationInput , request , response , listenerHandler ).join ();
45+ handle ( invoke ( invocationInput , request , response ) , request , response , listenerHandler ).join ();
4446 }
4547 }
4648
@@ -54,10 +56,10 @@ private void invokeAndHandleAsync(
5456 ? request .getAsyncContext ()
5557 : request .startAsync (request , response );
5658 asyncContext .setTimeout (configuration .getAsyncTimeout ());
57- AtomicReference <CompletableFuture < Void > > futureHolder = new AtomicReference <>();
59+ AtomicReference <FutureExecutionResult > futureHolder = new AtomicReference <>();
5860 AsyncTimeoutListener timeoutListener =
5961 event -> {
60- Optional .ofNullable (futureHolder .get ()).ifPresent (it -> it . cancel ( true ) );
62+ Optional .ofNullable (futureHolder .get ()).ifPresent (FutureExecutionResult :: cancel );
6163 writeResultResponse (
6264 invocationInput ,
6365 GraphQLQueryResult .create (
@@ -68,22 +70,27 @@ private void invokeAndHandleAsync(
6870 };
6971 asyncContext .addListener (timeoutListener );
7072 asyncContext .start (
71- () ->
72- futureHolder .set (
73- invokeAndHandle (invocationInput , request , response , listenerHandler )
74- .thenAccept (aVoid -> asyncContext .complete ())));
73+ () -> {
74+ FutureExecutionResult futureResult = invoke (invocationInput , request , response );
75+ futureHolder .set (futureResult );
76+ handle (futureResult , request , response , listenerHandler );
77+ });
7578 }
7679
77- private CompletableFuture <Void > invokeAndHandle (
78- GraphQLInvocationInput invocationInput ,
80+ private CompletableFuture <Void > handle (
81+ FutureExecutionResult futureResult ,
7982 HttpServletRequest request ,
8083 HttpServletResponse response ,
8184 ListenerHandler listenerHandler ) {
82- return invoke (invocationInput , request , response )
83- .thenAccept (it -> writeResultResponse (invocationInput , it , request , response ))
85+ return futureResult
86+ .thenApplyQueryResult ()
87+ .thenAccept (
88+ it -> writeResultResponse (futureResult .getInvocationInput (), it , request , response ))
8489 .thenAccept (it -> listenerHandler .onSuccess ())
8590 .exceptionally (
86- t -> writeErrorResponse (invocationInput , request , response , listenerHandler , t ))
91+ t ->
92+ writeErrorResponse (
93+ futureResult .getInvocationInput (), request , response , listenerHandler , t ))
8794 .thenAccept (it -> listenerHandler .onFinally ());
8895 }
8996
@@ -106,22 +113,32 @@ private Void writeErrorResponse(
106113 HttpServletResponse response ,
107114 ListenerHandler listenerHandler ,
108115 Throwable t ) {
116+ Throwable cause = getCause (t );
109117 if (!response .isCommitted ()) {
110118 writeResultResponse (
111- invocationInput , GraphQLQueryResult .create (toErrorResult (t )), request , response );
112- listenerHandler .onError (t );
119+ invocationInput , GraphQLQueryResult .create (toErrorResult (cause )), request , response );
120+ listenerHandler .onError (cause );
113121 } else {
114122 log .warn (
115123 "Cannot write GraphQL response, because the HTTP response is already committed. It most likely timed out." );
116124 }
117125 return null ;
118126 }
119127
128+ private Throwable getCause (Throwable t ) {
129+ return t instanceof CompletionException && t .getCause () != null ? t .getCause () : t ;
130+ }
131+
120132 private ExecutionResult toErrorResult (Throwable t ) {
121133 String message =
122- t instanceof CompletionException && t .getCause () != null
123- ? t .getCause ().getMessage ()
134+ t instanceof CancellationException
135+ ? "Execution canceled because timeout of "
136+ + configuration .getAsyncTimeout ()
137+ + " millis was reached"
124138 : t .getMessage ();
139+ if (message == null ) {
140+ message = "Unexpected error occurred" ;
141+ }
125142 return new ExecutionResultImpl (new GenericGraphQLError (message ));
126143 }
127144
@@ -130,28 +147,28 @@ protected QueryResponseWriter createWriter(
130147 return queryResponseWriterFactory .createWriter (invocationInput , queryResult , configuration );
131148 }
132149
133- private CompletableFuture < GraphQLQueryResult > invoke (
150+ private FutureExecutionResult invoke (
134151 GraphQLInvocationInput invocationInput ,
135152 HttpServletRequest request ,
136153 HttpServletResponse response ) {
137154 if (invocationInput instanceof GraphQLSingleInvocationInput ) {
138- return graphQLInvoker .queryAsync (invocationInput );
155+ return graphQLInvoker .execute (invocationInput );
139156 }
140157 return invokeBatched ((GraphQLBatchedInvocationInput ) invocationInput , request , response );
141158 }
142159
143- private CompletableFuture < GraphQLQueryResult > invokeBatched (
160+ private FutureExecutionResult invokeBatched (
144161 GraphQLBatchedInvocationInput batchedInvocationInput ,
145162 HttpServletRequest request ,
146163 HttpServletResponse response ) {
147164 BatchInputPreProcessor preprocessor = configuration .getBatchInputPreProcessor ();
148165 BatchInputPreProcessResult result =
149166 preprocessor .preProcessBatch (batchedInvocationInput , request , response );
150167 if (result .isExecutable ()) {
151- return graphQLInvoker .queryAsync (result .getBatchedInvocationInput ());
168+ return graphQLInvoker .execute (result .getBatchedInvocationInput ());
152169 }
153170
154- return CompletableFuture . completedFuture (
171+ return FutureExecutionResult . error (
155172 GraphQLQueryResult .createError (result .getStatusCode (), result .getStatusMessage ()));
156173 }
157174}
0 commit comments