Skip to content

Commit 70ee2f4

Browse files
committed
feat: allow customizing coroutine dispatcher for kfuncs
1 parent e4184cb commit 70ee2f4

File tree

4 files changed

+28
-2
lines changed

4 files changed

+28
-2
lines changed

graphql-dgs-spring-graphql/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
dependencies {
1818
implementation(project(":graphql-dgs"))
1919
implementation(project(":graphql-dgs-reactive"))
20+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
2021
implementation("org.springframework:spring-web")
2122
implementation("org.springframework.boot:spring-boot-autoconfigure")
2223
implementation("io.micrometer:context-propagation")

graphql-dgs-spring-graphql/src/main/kotlin/com/netflix/graphql/dgs/springgraphql/autoconfig/DgsSpringGraphQLAutoConfiguration.kt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ import graphql.schema.idl.TypeDefinitionRegistry
8585
import io.micrometer.context.ContextRegistry
8686
import io.micrometer.context.ContextSnapshotFactory
8787
import io.micrometer.context.integration.Slf4jThreadLocalAccessor
88+
import kotlinx.coroutines.CoroutineDispatcher
89+
import kotlinx.coroutines.Dispatchers
8890
import org.reactivestreams.Publisher
8991
import org.slf4j.Logger
9092
import org.slf4j.LoggerFactory
@@ -484,10 +486,21 @@ open class DgsSpringGraphQLAutoConfiguration(
484486
return executor
485487
}
486488

489+
/**
490+
* Default CoroutineDispatcher used for executing Kotlin suspend functions in data fetchers.
491+
* Defaults to [Dispatchers.Unconfined] which runs coroutines immediately on the calling thread.
492+
* Override this bean to customize the dispatcher for your specific use case.
493+
*/
494+
@Bean
495+
@Qualifier("dgsCoroutineDispatcher")
496+
@ConditionalOnMissingBean(name = ["dgsCoroutineDispatcher"])
497+
open fun dgsCoroutineDispatcher(): CoroutineDispatcher = Dispatchers.Unconfined
498+
487499
@Bean
488500
open fun methodDataFetcherFactory(
489501
argumentResolvers: ObjectProvider<ArgumentResolver>,
490502
@Qualifier("dgsAsyncTaskExecutor") taskExecutorOptional: Optional<AsyncTaskExecutor>,
503+
@Qualifier("dgsCoroutineDispatcher") coroutineDispatcher: CoroutineDispatcher,
491504
): MethodDataFetcherFactory {
492505
val taskExecutor =
493506
if (taskExecutorOptional.isPresent) {
@@ -496,7 +509,12 @@ open class DgsSpringGraphQLAutoConfiguration(
496509
null
497510
}
498511

499-
return MethodDataFetcherFactory(argumentResolvers.orderedStream().toList(), DefaultParameterNameDiscoverer(), taskExecutor)
512+
return MethodDataFetcherFactory(
513+
argumentResolvers.orderedStream().toList(),
514+
DefaultParameterNameDiscoverer(),
515+
taskExecutor,
516+
coroutineDispatcher,
517+
)
500518
}
501519

502520
@Bean

graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/DataFetcherInvoker.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.netflix.graphql.dgs.internal
1919
import com.netflix.graphql.dgs.internal.method.ArgumentResolverComposite
2020
import graphql.schema.DataFetcher
2121
import graphql.schema.DataFetchingEnvironment
22+
import kotlinx.coroutines.CoroutineDispatcher
2223
import kotlinx.coroutines.Dispatchers
2324
import kotlinx.coroutines.reactor.mono
2425
import org.springframework.core.BridgeMethodResolver
@@ -43,6 +44,7 @@ class DataFetcherInvoker internal constructor(
4344
private val resolvers: ArgumentResolverComposite,
4445
parameterNameDiscoverer: ParameterNameDiscoverer,
4546
taskExecutor: AsyncTaskExecutor?,
47+
private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Unconfined,
4648
) : DataFetcher<Any?> {
4749
private val bridgedMethod: Method = BridgeMethodResolver.findBridgedMethod(method)
4850
private val kotlinFunction: KFunction<*>? =
@@ -131,7 +133,7 @@ class DataFetcherInvoker internal constructor(
131133
}
132134

133135
if (kFunc.isSuspend) {
134-
return mono(Dispatchers.Unconfined) {
136+
return mono(coroutineDispatcher) {
135137
kFunc.callSuspendBy(argsByName)
136138
}.onErrorMap(InvocationTargetException::class.java) { it.targetException }
137139
}

graphql-dgs/src/main/kotlin/com/netflix/graphql/dgs/internal/method/MethodDataFetcherFactory.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import graphql.TrivialDataFetcher
2222
import graphql.schema.DataFetcher
2323
import graphql.schema.DataFetchingEnvironment
2424
import graphql.schema.FieldCoordinates
25+
import kotlinx.coroutines.CoroutineDispatcher
26+
import kotlinx.coroutines.Dispatchers
2527
import org.springframework.core.DefaultParameterNameDiscoverer
2628
import org.springframework.core.MethodParameter
2729
import org.springframework.core.ParameterNameDiscoverer
@@ -39,6 +41,7 @@ class MethodDataFetcherFactory(
3941
argumentResolvers: List<ArgumentResolver>,
4042
internal val parameterNameDiscoverer: ParameterNameDiscoverer = DefaultParameterNameDiscoverer(),
4143
private val asyncTaskExecutor: AsyncTaskExecutor? = null,
44+
private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Unconfined,
4245
) {
4346
private val resolvers = ArgumentResolverComposite(argumentResolvers)
4447

@@ -55,6 +58,7 @@ class MethodDataFetcherFactory(
5558
resolvers = resolvers,
5659
parameterNameDiscoverer = parameterNameDiscoverer,
5760
taskExecutor = null,
61+
coroutineDispatcher = coroutineDispatcher,
5862
)
5963
return object : TrivialDataFetcher<Any?> {
6064
override fun get(environment: DataFetchingEnvironment): Any? = methodDataFetcher.get(environment)
@@ -69,6 +73,7 @@ class MethodDataFetcherFactory(
6973
resolvers = resolvers,
7074
parameterNameDiscoverer = parameterNameDiscoverer,
7175
taskExecutor = asyncTaskExecutor,
76+
coroutineDispatcher = coroutineDispatcher,
7277
)
7378
}
7479

0 commit comments

Comments
 (0)