Skip to content

Commit a15a68a

Browse files
author
Samuel Vazquez
committed
feat: add comments
1 parent c1e3743 commit a15a68a

File tree

9 files changed

+111
-90
lines changed

9 files changed

+111
-90
lines changed

executions/graphql-kotlin-dataloader-instrumentation/src/main/kotlin/com/expediagroup/graphql/dataloader/instrumentation/extensions/CompletableFutureExtensions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fun <V> CompletableFuture<V>.dispatchIfNeeded(
3939
.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
4040
?: throw MissingInstrumentationStateException()
4141

42-
if (syncExecutionExhaustedState.dataLoadersInvokedAfterDispatch() && syncExecutionExhaustedState.allSyncExecutionsExhausted()) {
42+
if (syncExecutionExhaustedState.dataLoadersLoadInvokedAfterDispatchAll() && syncExecutionExhaustedState.allSyncExecutionsExhausted()) {
4343
dataLoaderRegistry.dispatchAll()
4444
}
4545
return this

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,26 @@
1616

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

19+
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.DataLoaderRegistryState
1920
import com.expediagroup.graphql.dataloader.instrumentation.syncexhaustion.state.SyncExecutionExhaustedState
2021
import org.dataloader.DataLoader
2122
import org.dataloader.instrumentation.DataLoaderInstrumentation
2223
import org.dataloader.instrumentation.DataLoaderInstrumentationContext
2324

25+
/**
26+
* Custom [DataLoaderInstrumentation] implementation that helps to calculate the state of [DataLoader]s in the
27+
* [DataLoaderRegistryState] that lives inside the [syncExecutionExhaustedState]
28+
*/
2429
class DataLoaderSyncExecutionExhaustedDataLoaderDispatcher(
2530
private val syncExecutionExhaustedState: SyncExecutionExhaustedState
26-
): DataLoaderInstrumentation {
27-
31+
) : DataLoaderInstrumentation {
2832
private val contextForSyncExecutionExhausted: DataLoaderInstrumentationContext<Any?> =
29-
object: DataLoaderInstrumentationContext<Any?> {
33+
object : DataLoaderInstrumentationContext<Any?> {
3034
override fun onDispatched() {
31-
syncExecutionExhaustedState.onDataLoaderPromiseDispatched()
35+
syncExecutionExhaustedState.onDataLoaderLoadDispatched()
3236
}
3337
override fun onCompleted(result: Any?, t: Throwable?) {
34-
syncExecutionExhaustedState.onDataLoaderPromiseCompleted(result, t)
38+
syncExecutionExhaustedState.onDataLoaderLoadCompleted()
3539
}
3640
}
3741

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import graphql.execution.instrumentation.InstrumentationState
3030
import graphql.execution.instrumentation.SimplePerformantInstrumentation
3131
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters
3232
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters
33-
import graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters
3433
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
3534

3635
/**
@@ -74,12 +73,4 @@ class GraphQLSyncExecutionExhaustedDataLoaderDispatcher : SimplePerformantInstru
7473
parameters.executionContext.takeUnless(ExecutionContext::isMutation)
7574
?.graphQLContext?.get<SyncExecutionExhaustedState>(SyncExecutionExhaustedState::class)
7675
?.beginFieldFetching(parameters)
77-
78-
override fun beginFieldCompletion(
79-
parameters: InstrumentationFieldCompleteParameters,
80-
state: InstrumentationState?
81-
): InstrumentationContext<Any>? {
82-
println("field completed: ${parameters.fetchedValue}")
83-
return super.beginFieldCompletion(parameters, state)
84-
}
8576
}

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

Lines changed: 0 additions & 58 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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.state
18+
19+
import org.dataloader.DataLoader
20+
import org.dataloader.DataLoaderRegistry
21+
import java.util.concurrent.CompletableFuture
22+
import java.util.concurrent.atomic.AtomicInteger
23+
24+
/**
25+
* Calculate the state of [DataLoader.load]s in a [DataLoaderRegistry]
26+
*/
27+
class DataLoaderRegistryState {
28+
/**
29+
* Count [DataLoader.load] invocations
30+
*/
31+
private val loadCounter = AtomicInteger(0)
32+
33+
/**
34+
* Snapshot of [loadCounter] when [DataLoaderRegistry.dispatchAll] is invoked,
35+
* then on every load complete decrease it
36+
*/
37+
private val onDispatchAllLoadCounter = AtomicInteger(0)
38+
39+
/**
40+
* Take snapshot of [loadCounter] when [DataLoaderRegistry.dispatchAll] is invoked
41+
*/
42+
fun takeSnapshot() {
43+
onDispatchAllLoadCounter.set(loadCounter.get())
44+
loadCounter.set(0)
45+
}
46+
47+
/**
48+
* @return if all [CompletableFuture]s returned by [DataLoader.load] were completed
49+
*/
50+
fun onDispatchAllFuturesCompleted(): Boolean =
51+
onDispatchAllLoadCounter.get() == 0
52+
53+
/**
54+
* @return If more [DataLoader.load] where invoked after the [DataLoaderRegistry.dispatchAll] invocation
55+
*/
56+
fun dataLoadersLoadInvokedAfterDispatchAll(): Boolean =
57+
loadCounter.get() > 0
58+
59+
/**
60+
* Increase [loadCounter] when [DataLoader.load] is invoked
61+
*/
62+
fun onDataLoaderLoadDispatched() {
63+
loadCounter.incrementAndGet()
64+
}
65+
66+
/**
67+
* Decrease [onDispatchAllLoadCounter] when [DataLoader.load] returned [CompletableFuture] completes
68+
*/
69+
fun onDataLoaderLoadCompleted() {
70+
onDispatchAllLoadCounter.decrementAndGet()
71+
}
72+
}

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

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import graphql.execution.instrumentation.parameters.InstrumentationExecutionPara
2929
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters
3030
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
3131
import graphql.schema.DataFetcher
32+
import org.dataloader.DataLoader
3233
import org.dataloader.DataLoaderRegistry
3334
import java.util.concurrent.CompletableFuture
3435
import java.util.concurrent.ConcurrentHashMap
@@ -42,9 +43,9 @@ class SyncExecutionExhaustedState(
4243
totalOperations: Int,
4344
private val dataLoaderRegistryProvider: () -> DataLoaderRegistry
4445
) {
45-
private val totalExecutions: AtomicInteger = AtomicInteger(totalOperations)
46+
private val totalExecutions = AtomicInteger(totalOperations)
4647
private val executions = ConcurrentHashMap<ExecutionId, ExecutionInputState>()
47-
private val dataLoadersDispatchState = DataLoaderDispatchState()
48+
private val dataLoadersDispatchState = DataLoaderRegistryState()
4849

4950
/**
5051
* Create the [ExecutionInputState] When a specific [ExecutionInput] starts his execution
@@ -107,7 +108,7 @@ class SyncExecutionExhaustedState(
107108
}
108109

109110
/**
110-
* This is called just before a field [DataFetcher] is invoked
111+
* This is invoked just before a field [DataFetcher] is invoked
111112
*
112113
* @param parameters contains information of which field will start the fetching
113114
* @return a [InstrumentationContext] object that will be called back when the [DataFetcher]
@@ -153,16 +154,21 @@ class SyncExecutionExhaustedState(
153154
}
154155
}
155156

156-
fun dataLoadersInvokedAfterDispatch(): Boolean =
157-
dataLoadersDispatchState.dataLoadersInvokedAfterDispatch()
157+
fun dataLoadersLoadInvokedAfterDispatchAll(): Boolean =
158+
dataLoadersDispatchState.dataLoadersLoadInvokedAfterDispatchAll()
158159

159-
fun onDataLoaderPromiseDispatched() {
160-
dataLoadersDispatchState.onDataLoaderPromiseDispatched()
160+
/**
161+
* This is invoked right after a [DataLoader.load] was dispatched
162+
*/
163+
fun onDataLoaderLoadDispatched() {
164+
dataLoadersDispatchState.onDataLoaderLoadDispatched()
161165
}
162166

163-
fun onDataLoaderPromiseCompleted(result: Any?, t: Throwable?) {
164-
dataLoadersDispatchState.onDataLoaderPromiseCompleted(result, t)
165-
// println("completed dataloader promise: $result")
167+
/**
168+
* This is invoked right after a [DataLoader.load] was completed
169+
*/
170+
fun onDataLoaderLoadCompleted() {
171+
dataLoadersDispatchState.onDataLoaderLoadCompleted()
166172
if (allSyncExecutionsExhausted()) {
167173
dataLoaderRegistryProvider.invoke().dispatchAll()
168174
}
@@ -175,7 +181,7 @@ class SyncExecutionExhaustedState(
175181
*/
176182
fun allSyncExecutionsExhausted(): Boolean =
177183
synchronized(executions) {
178-
if (executions.size < totalExecutions.get() || !dataLoadersDispatchState.onDispatchFuturesHandled())
184+
if (executions.size < totalExecutions.get() || !dataLoadersDispatchState.onDispatchAllFuturesCompleted())
179185
return false
180186

181187
if (executions.values.all(ExecutionInputState::isSyncExecutionExhausted)) {

executions/graphql-kotlin-dataloader-instrumentation/src/test/kotlin/com/expediagroup/graphql/dataloader/instrumentation/fixture/ProductGraphQL.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ object ProductGraphQL {
140140
ExecutionInput
141141
.newExecutionInput(query)
142142
.dataLoaderRegistry(dataLoaderRegistry)
143-
.graphQLContext { it.of(graphQLContext) }
143+
.graphQLContext { it.of(graphQLContext) }
144144
.build()
145145
).await()
146146
}

executions/graphql-kotlin-dataloader/src/main/kotlin/com/expediagroup/graphql/dataloader/KotlinDataLoaderRegistryFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.dataloader.instrumentation.DataLoaderInstrumentation
2626
class KotlinDataLoaderRegistryFactory(
2727
private val dataLoaders: List<KotlinDataLoader<*, *>>
2828
) {
29-
constructor(): this(emptyList())
29+
constructor() : this(emptyList())
3030

3131
/**
3232
* Generate [DataLoaderRegistry] to be used for GraphQL request execution.

executions/graphql-kotlin-dataloader/src/test/kotlin/com/expediagroup/graphql/dataloader/KotlinDataLoaderRegistryFactoryTest.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import graphql.GraphQLContext
2020
import io.mockk.mockk
2121
import org.dataloader.DataLoader
2222
import org.dataloader.DataLoaderFactory
23-
import org.dataloader.instrumentation.ChainedDataLoaderInstrumentation
23+
import org.dataloader.instrumentation.DataLoaderInstrumentation
2424
import org.junit.jupiter.api.Test
2525
import reactor.kotlin.core.publisher.toFlux
2626
import kotlin.test.assertEquals
@@ -29,7 +29,7 @@ import kotlin.test.assertTrue
2929
class KotlinDataLoaderRegistryFactoryTest {
3030
@Test
3131
fun `generate registry with empty list`() {
32-
val registry = KotlinDataLoaderRegistryFactory().generate(mockk())
32+
val registry = KotlinDataLoaderRegistryFactory().generate(mockk(relaxed = true))
3333
assertTrue(registry.dataLoaders.isEmpty())
3434
}
3535

@@ -43,10 +43,16 @@ class KotlinDataLoaderRegistryFactoryTest {
4343
}
4444
}
4545

46+
val customInstrumentation = object : DataLoaderInstrumentation {
47+
48+
}
4649
val registry = KotlinDataLoaderRegistryFactory(
4750
listOf(mockLoader)
48-
).generate(mockk())
51+
).generate(
52+
mockk(relaxed = true),
53+
customInstrumentation
54+
)
4955
assertEquals(1, registry.dataLoaders.size)
50-
assertTrue(registry.instrumentation is ChainedDataLoaderInstrumentation)
56+
assertEquals(customInstrumentation, registry.instrumentation)
5157
}
5258
}

0 commit comments

Comments
 (0)