Skip to content

Commit 7fb2729

Browse files
authored
Merge pull request #4207 from tinnou/onExceptionHandled-chained-instrumentation
Call onExceptionHandled in ChainedInstrumentation
2 parents c465601 + 835e9db commit 7fb2729

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

src/main/java/graphql/execution/instrumentation/ChainedInstrumentation.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import graphql.ExperimentalApi;
77
import graphql.PublicApi;
88
import graphql.execution.Async;
9+
import graphql.execution.DataFetcherResult;
910
import graphql.execution.ExecutionContext;
1011
import graphql.execution.FieldValueInfo;
1112
import graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters;
@@ -380,6 +381,11 @@ public void onFetchedValue(Object fetchedValue) {
380381
contexts.forEach(context -> context.onFetchedValue(fetchedValue));
381382
}
382383

384+
@Override
385+
public void onExceptionHandled(DataFetcherResult<Object> dataFetcherResult) {
386+
contexts.forEach(context -> context.onExceptionHandled(dataFetcherResult));
387+
}
388+
383389
@Override
384390
public void onCompleted(Object result, Throwable t) {
385391
contexts.forEach(context -> context.onCompleted(result, t));

src/test/groovy/graphql/execution/instrumentation/ChainedInstrumentationStateTest.groovy

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import graphql.execution.AsyncExecutionStrategy
88
import graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters
99
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters
1010
import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters
11+
import graphql.schema.DataFetcher
12+
import graphql.schema.DataFetchingEnvironment
1113
import graphql.validation.ValidationError
1214
import spock.lang.Specification
1315

@@ -227,6 +229,78 @@ class ChainedInstrumentationStateTest extends Specification {
227229
assertCalls(c)
228230
}
229231

232+
def "basic chaining and state management when exception raised in data fetching"() {
233+
234+
def a = new NamedInstrumentation("A")
235+
def b = new NamedInstrumentation("B")
236+
def c = new NamedInstrumentation("C")
237+
def nullState = new SimplePerformantInstrumentation()
238+
239+
def chainedInstrumentation = new ChainedInstrumentation([
240+
a,
241+
b,
242+
nullState,
243+
c,
244+
])
245+
246+
def query = """
247+
query HeroNameAndFriendsQuery {
248+
hero {
249+
id
250+
}
251+
}
252+
"""
253+
254+
def expected = "onExceptionHandled:fetch-id"
255+
256+
257+
when:
258+
def strategy = new AsyncExecutionStrategy()
259+
def schema = StarWarsSchema.starWarsSchema
260+
def graphQL = GraphQL
261+
.newGraphQL(schema.transform { schemaBuilder ->
262+
// throw exception when fetching the hero id
263+
def exceptionDataFetcher = new DataFetcher() {
264+
@Override
265+
Object get(DataFetchingEnvironment environment) {
266+
throw new RuntimeException("Data fetcher exception")
267+
}
268+
}
269+
schemaBuilder.codeRegistry(schema.codeRegistry.transform {
270+
it.dataFetcher(
271+
schema.getObjectType("Human"),
272+
schema.getObjectType("Human").getFieldDefinition("id"),
273+
exceptionDataFetcher
274+
)
275+
it.dataFetcher(
276+
schema.getObjectType("Droid"),
277+
schema.getObjectType("Droid").getFieldDefinition("id"),
278+
exceptionDataFetcher
279+
)
280+
return it
281+
}
282+
)
283+
})
284+
.queryExecutionStrategy(strategy)
285+
.instrumentation(chainedInstrumentation)
286+
.build()
287+
288+
graphQL.execute(query)
289+
290+
then:
291+
292+
chainedInstrumentation.getInstrumentations().size() == 4
293+
294+
a.executionList.any { it == expected }
295+
b.executionList.any { it == expected }
296+
c.executionList.any { it == expected }
297+
298+
assertCalls(a)
299+
assertCalls(b)
300+
assertCalls(c)
301+
302+
}
303+
230304
def "empty chain"() {
231305
def chainedInstrumentation = new ChainedInstrumentation(Arrays.asList())
232306

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
package graphql.execution.instrumentation
22

3+
import graphql.execution.DataFetcherResult
4+
35
class TestingFieldFetchingInstrumentationContext extends TestingInstrumentContext<Object> implements FieldFetchingInstrumentationContext {
46

57
TestingFieldFetchingInstrumentationContext(Object op, Object executionList, Object throwableList, Boolean useOnDispatch) {
68
super(op, executionList, throwableList, useOnDispatch)
79
}
10+
11+
@Override
12+
void onExceptionHandled(DataFetcherResult<Object> dataFetcherResult) {
13+
executionList << "onExceptionHandled:$op"
14+
}
815
}
916

src/test/groovy/graphql/execution/instrumentation/TestingInstrumentContext.groovy

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package graphql.execution.instrumentation
22

3-
import java.util.concurrent.CompletableFuture
4-
53
class TestingInstrumentContext<T> implements InstrumentationContext<T> {
64
def op
75
def start = System.currentTimeMillis()

0 commit comments

Comments
 (0)