Skip to content

Commit 9e318b3

Browse files
samuelAndalonSamuel Vazquez
andauthored
feat: graphql java 23 update (#2106)
### 📝 Description https://github.com/graphql-java/graphql-java/releases/tag/v23.1 https://github.com/graphql-java/graphql-java/releases/tag/v23.0 graphql-java 22 introduced the support to `@defer` directive, however, it wasn't added to the SDL, now in graphql-java 23 `@defer` is being, added. For now, we will disable `@defer` because work will be needed to implement the transport of responses through HTTP. graphql-java 23 broke the data loader dispatch by synchronous execution exhaustion mechanism, because of the introduction of dataLoader hooks, the reason is because the mechanism was relying on the number of dependents of the CompletableFuture returned by the dataLoader, which now is instrumented and adds extra dependents. significant changes were done to stop relying on number of dependents and instead, use the instrumentation provided by the data loader library A KotlinDataLoaderRegistry decorator is no longer needed, with this we will simply the execution. --------- Co-authored-by: Samuel Vazquez <[email protected]>
1 parent 7b9676c commit 9e318b3

File tree

61 files changed

+747
-867
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+747
-867
lines changed

executions/graphql-kotlin-dataloader-instrumentation/README.md

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Javadocs](https://img.shields.io/maven-central/v/com.expediagroup/graphql-kotlin-dataloader-instrumentation.svg?label=javadoc&colorB=brightgreen)](https://www.javadoc.io/doc/com.expediagroup/graphql-kotlin-dataloader-instrumentation)
44

55
`graphql-kotlin-dataloader-instrumentation` is set of custom instrumentations that will signal when is the right moment
6-
to dispatch a `KotlinDataLoaderRegistry`.
6+
to dispatch a `DataLoaderRegistry`.
77

88
This instrumentation follows the same approach of the [DataLoaderDispatcherInstrumentation](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/instrumentation/dataloader/DataLoaderDispatcherInstrumentation.java).
99

@@ -32,19 +32,17 @@ implementation("com.expediagroup:graphql-kotlin-dataloader-instrumentation:$late
3232

3333
## Use it
3434

35-
When creating your `GraphQL` instance make sure to include either
36-
`DataLoaderLevelDispatchedInstrumentation` or `DataLoaderSyncExecutionExhaustedInstrumentation`.
35+
When creating your `GraphQL` instance make sure to include an instance of `GraphQLSyncExecutionExhaustedDataLoaderDispatcher`
3736

3837
```kotlin
3938
GraphQL
40-
.instrumentation(DataLoaderSyncExecutionExhaustedInstrumentation())
39+
.instrumentation(GraphQLSyncExecutionExhaustedDataLoaderDispatcher())
4140
// configure schema, type wiring, etc.
4241
.build()
4342
```
4443

45-
When ready to execute an operation or operations create a `GraphQLContext` instance with one of the following entries:
46-
- An instance of `ExecutionLevelDispatchedState` if you choose `DataLoaderLevelDispatchedInstrumentation`.
47-
- An instance of `SyncExecutionExhaustedState` if you choose `DataLoaderSyncExecutionExhaustedInstrumentation`.
44+
When ready to execute an operation or operations create a `GraphQLContext` instance with an instance of
45+
`SyncExecutionExhaustedState`
4846

4947

5048
```kotlin
@@ -66,22 +64,19 @@ val queries = [
6664
]
6765

6866
val graphQLContext = mapOf(
69-
SyncExecutionExhaustedState::class to SyncExecutionExhaustedState(
70-
queries.size,
71-
kotlinDataLoaderRegistry
72-
)
67+
SyncExecutionExhaustedState::class to SyncExecutionExhaustedState(queries.size) {
68+
dataLoaderRegistry
69+
}
7370
)
7471

75-
val executionInput1 = ExecutionInput.newExecutionInput(queries[0]).graphQLContext(graphQLContext).dataLoaderRegistry(kotlinDataLoaderRegistry).build()
76-
val executionInput2 = ExecutionInput.newExecutionInput(queries[1]).graphQLContext(graphQLContext).dataLoaderRegistry(kotlinDataLoaderRegistry).build()
72+
val executionInput1 = ExecutionInput.newExecutionInput(queries[0]).graphQLContext(graphQLContext).dataLoaderRegistry(dataLoaderRegistry).build()
73+
val executionInput2 = ExecutionInput.newExecutionInput(queries[1]).graphQLContext(graphQLContext).dataLoaderRegistry(dataLoaderRegistry).build()
7774

7875
val result1 = graphQL.executeAsync(executionInput1)
7976
val result2 = graphQL.executeAsync(executionInput2)
8077
```
8178

82-
- `DataLoaderLevelDispatchedInstrumentation` will dispatch the `KotlinDataLoaderRegistry` instance when
83-
a certain level of all executionInputs was dispatched (all DataFetchers were invoked).
84-
- `DataLoaderSyncExecutionExhaustedInstrumentation` will dispatch the `KotlinDataLoaderRegistry` instance when
79+
the `GraphQLSyncExecutionExhaustedDataLoaderDispatcher` will dispatch the `DataLoaderRegistry` when
8580
the synchronous execution of an operation exhausted (synchronous execution will be exhausted when all data fetchers
8681
of all paths executed up until a scalar leaf, or a `CompletableFuture`).
8782

executions/graphql-kotlin-dataloader-instrumentation/src/main/kotlin/com/expediagroup/graphql/dataloader/instrumentation/exceptions/MissingKotlinDataLoaderRegistryException.kt

Lines changed: 0 additions & 25 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 Expedia, Inc
2+
* Copyright 2025 Expedia, Inc
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,35 +16,31 @@
1616

1717
package com.expediagroup.graphql.dataloader.instrumentation.extensions
1818

19-
import com.expediagroup.graphql.dataloader.KotlinDataLoaderRegistry
2019
import com.expediagroup.graphql.dataloader.instrumentation.exceptions.MissingInstrumentationStateException
21-
import com.expediagroup.graphql.dataloader.instrumentation.exceptions.MissingKotlinDataLoaderRegistryException
2220
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.SyncExecutionExhaustedState
2321
import graphql.schema.DataFetchingEnvironment
2422
import org.dataloader.DataLoader
23+
import org.dataloader.DataLoaderRegistry
2524
import java.util.concurrent.CompletableFuture
2625

2726
/**
28-
* Check if all futures collected on [KotlinDataLoaderRegistry.dispatchAll] were handled
27+
* Check if all futures collected on [DataLoaderRegistry.dispatchAll] were handled
2928
* and if we have more futures than we had when we started to dispatch, if so,
3029
* means that [DataLoader]s were chained, so we need to dispatch the dataLoaderRegistry.
30+
*
31+
* @throws MissingInstrumentationStateException if a [SyncExecutionExhaustedState] instance is not present in the graphQLContext
3132
*/
3233
fun <V> CompletableFuture<V>.dispatchIfNeeded(
3334
environment: DataFetchingEnvironment
3435
): CompletableFuture<V> {
35-
val dataLoaderRegistry = environment.dataLoaderRegistry as? KotlinDataLoaderRegistry ?: throw MissingKotlinDataLoaderRegistryException()
36+
val dataLoaderRegistry = environment.dataLoaderRegistry
37+
val syncExecutionExhaustedState = environment
38+
.graphQlContext
39+
.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
40+
?: throw MissingInstrumentationStateException()
3641

37-
if (dataLoaderRegistry.dataLoadersInvokedOnDispatch()) {
38-
when {
39-
environment.graphQlContext.hasKey(SyncExecutionExhaustedState::class) -> {
40-
environment
41-
.graphQlContext.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
42-
.ifAllSyncExecutionsExhausted {
43-
dataLoaderRegistry.dispatchAll()
44-
}
45-
}
46-
else -> throw MissingInstrumentationStateException()
47-
}
42+
if (syncExecutionExhaustedState.dataLoadersLoadInvokedAfterDispatchAll() && syncExecutionExhaustedState.allSyncExecutionsExhausted()) {
43+
dataLoaderRegistry.dispatchAll()
4844
}
4945
return this
5046
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2025 Expedia, Inc
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion
18+
19+
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.DataLoaderRegistryState
20+
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.SyncExecutionExhaustedState
21+
import org.dataloader.DataLoader
22+
import org.dataloader.instrumentation.DataLoaderInstrumentation
23+
import org.dataloader.instrumentation.DataLoaderInstrumentationContext
24+
25+
/**
26+
* Custom [DataLoaderInstrumentation] implementation that helps to calculate the state of [DataLoader]s in the
27+
* [DataLoaderRegistryState] that lives inside the [syncExecutionExhaustedState]
28+
*/
29+
class DataLoaderSyncExecutionExhaustedDataLoaderDispatcher(
30+
private val syncExecutionExhaustedState: SyncExecutionExhaustedState
31+
) : DataLoaderInstrumentation {
32+
private val contextForSyncExecutionExhausted: DataLoaderInstrumentationContext<Any?> =
33+
object : DataLoaderInstrumentationContext<Any?> {
34+
override fun onDispatched() {
35+
syncExecutionExhaustedState.onDataLoaderLoadDispatched()
36+
}
37+
override fun onCompleted(result: Any?, t: Throwable?) {
38+
syncExecutionExhaustedState.onDataLoaderLoadCompleted()
39+
}
40+
}
41+
42+
override fun beginLoad(
43+
dataLoader: DataLoader<*, *>,
44+
key: Any,
45+
loadContext: Any?
46+
): DataLoaderInstrumentationContext<Any?> =
47+
contextForSyncExecutionExhausted
48+
}

executions/graphql-kotlin-dataloader-instrumentation/src/main/kotlin/com/expediagroup/graphql/dataloader/instrumentation/syncexhaustion/DataLoaderSyncExecutionExhaustedInstrumentation.kt

Lines changed: 0 additions & 47 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 Expedia, Inc
2+
* Copyright 2025 Expedia, Inc
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,15 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.execution
17+
package com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion
1818

1919
import com.expediagroup.graphql.dataloader.instrumentation.extensions.isMutation
2020
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.SyncExecutionExhaustedState
21-
import graphql.ExecutionInput
2221
import graphql.ExecutionResult
2322
import graphql.GraphQLContext
2423
import graphql.execution.ExecutionContext
25-
import graphql.execution.ExecutionId
2624
import graphql.execution.instrumentation.ExecuteObjectInstrumentationContext
2725
import graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext
2826
import graphql.execution.instrumentation.FieldFetchingInstrumentationContext
@@ -34,39 +32,19 @@ import graphql.execution.instrumentation.parameters.InstrumentationExecutionPara
3432
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters
3533
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
3634

37-
/**
38-
* typealias that represents the signature of a callback that will be executed when sync execution is exhausted
39-
*/
40-
internal typealias OnSyncExecutionExhaustedCallback = (List<ExecutionId>) -> Unit
41-
4235
/**
4336
* Custom GraphQL [Instrumentation] that calculate the synchronous execution exhaustion
4437
* of all GraphQL operations sharing the same [GraphQLContext]
4538
*/
46-
abstract class AbstractSyncExecutionExhaustedInstrumentation : SimplePerformantInstrumentation() {
47-
/**
48-
* This is invoked each time instrumentation attempts to calculate exhaustion state, this can be called from either
49-
* `beginFieldField.dispatch` or `beginFieldFetch.complete`.
50-
*
51-
* @param parameters contains information of which [ExecutionInput] caused the calculation
52-
* @return [OnSyncExecutionExhaustedCallback] to invoke when the synchronous execution of all operations was exhausted
53-
*/
54-
abstract fun getOnSyncExecutionExhaustedCallback(
55-
parameters: SyncExecutionExhaustedInstrumentationParameters
56-
): OnSyncExecutionExhaustedCallback
39+
class GraphQLSyncExecutionExhaustedDataLoaderDispatcher : SimplePerformantInstrumentation() {
5740

5841
override fun beginExecution(
5942
parameters: InstrumentationExecutionParameters,
6043
state: InstrumentationState?
6144
): InstrumentationContext<ExecutionResult>? =
6245
parameters.graphQLContext
6346
?.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
64-
?.beginExecution(
65-
parameters,
66-
this.getOnSyncExecutionExhaustedCallback(
67-
SyncExecutionExhaustedInstrumentationParameters(parameters.executionInput)
68-
)
69-
)
47+
?.beginExecution(parameters)
7048

7149
override fun beginExecutionStrategy(
7250
parameters: InstrumentationExecutionStrategyParameters,
@@ -94,10 +72,5 @@ abstract class AbstractSyncExecutionExhaustedInstrumentation : SimplePerformantI
9472
): FieldFetchingInstrumentationContext? =
9573
parameters.executionContext.takeUnless(ExecutionContext::isMutation)
9674
?.graphQLContext?.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
97-
?.beginFieldFetching(
98-
parameters,
99-
this.getOnSyncExecutionExhaustedCallback(
100-
SyncExecutionExhaustedInstrumentationParameters(parameters.executionContext.executionInput)
101-
)
102-
)
75+
?.beginFieldFetching(parameters)
10376
}

executions/graphql-kotlin-dataloader-instrumentation/src/main/kotlin/com/expediagroup/graphql/dataloader/instrumentation/syncexhaustion/execution/SyncExecutionExhaustedInstrumentationParameters.kt

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)