Skip to content

Commit

Permalink
Dataloader improvements (#1720)
Browse files Browse the repository at this point in the history
* Update example app to use chained data loader.

* Add a new config property for the schedule duration in ticker mode.

* Separate the config for data loaders.
  • Loading branch information
srinivasankavitha authored Nov 21, 2023
1 parent 5030829 commit 620e4b6
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2021 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.graphql.dgs.example.shared.dataLoader;

import com.netflix.graphql.dgs.DgsDataLoader;
import com.netflix.graphql.dgs.DgsDispatchPredicate;
import org.dataloader.BatchLoader;
import org.dataloader.registries.DispatchPredicate;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;

@DgsDataLoader(name = "greetings")
public class GreetingsDataLoader implements BatchLoader<String, String> {
@Override
public CompletionStage<List<String>> load(List<String> keys) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return CompletableFuture.supplyAsync(() -> keys.stream().map(key -> "Greetings, " + key + "!").collect(Collectors.toList()));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,21 @@ public String hello(@InputArgument String name) {
@DgsData(parentType = "Query", field = "messageFromBatchLoader")
public CompletableFuture<String> getMessage(DataFetchingEnvironment env) {
DataLoader<String, String> dataLoader = env.getDataLoader("messages");
DataLoader<String, String> dataLoaderB = env.getDataLoader("greetings");
return dataLoader.load("a");
}

@DgsData(parentType = "Query", field = "messageFromBatchLoaderWithGreetings")
public CompletableFuture<String> getGreetings(DataFetchingEnvironment env) {
DataLoader<String, String> dataLoaderA = env.getDataLoader("messages");
DataLoader<String, String> dataLoaderB = env.getDataLoader("greetings");
return dataLoaderB.load("a").thenCompose(key -> {
CompletableFuture<String> loadA = dataLoaderA.load(key);
dataLoaderA.dispatch();
return loadA;
});
}

@DgsData(parentType = "Query", field = "messageFromBatchLoaderWithScheduledDispatch")
public CompletableFuture<String> getMessageScheduled(DataFetchingEnvironment env) {
DataLoader<String, String> dataLoader = env.getDataLoader("messagesWithScheduledDispatch");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type Query {
withDataLoaderGraphQLContext: String
movies: [Movie]
messageFromBatchLoader: String
messageFromBatchLoaderWithGreetings: String
messagesWithExceptionFromBatchLoader: [Message]
messageFromBatchLoaderWithScheduledDispatch: String

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ import java.util.concurrent.ScheduledExecutorService
*/
@Suppress("SpringJavaInjectionPointsAutowiringInspection")
@AutoConfiguration
@EnableConfigurationProperties(DgsConfigurationProperties::class)
@EnableConfigurationProperties(DgsConfigurationProperties::class, DgsDataloaderConfigurationProperties::class)
@ImportAutoConfiguration(classes = [JacksonAutoConfiguration::class, DgsInputArgumentConfiguration::class])
open class DgsAutoConfiguration(
private val configProps: DgsConfigurationProperties
private val configProps: DgsConfigurationProperties,
private val dataloaderConfigProps: DgsDataloaderConfigurationProperties
) {

companion object {
Expand Down Expand Up @@ -164,7 +165,7 @@ open class DgsAutoConfiguration(

@Bean
open fun dgsDataLoaderProvider(applicationContext: ApplicationContext, dataloaderOptionProvider: DgsDataLoaderOptionsProvider, @Qualifier("dgsScheduledExecutorService") dgsScheduledExecutorService: ScheduledExecutorService): DgsDataLoaderProvider {
return DgsDataLoaderProvider(applicationContext, dataloaderOptionProvider, dgsScheduledExecutorService, configProps.dataloaderTickerModeEnabled)
return DgsDataLoaderProvider(applicationContext, dataloaderOptionProvider, dgsScheduledExecutorService, dataloaderConfigProps.scheduleDuration, dataloaderConfigProps.tickerModeEnabled)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ data class DgsConfigurationProperties(
/** Location of the GraphQL schema files. */
@DefaultValue(DEFAULT_SCHEMA_LOCATION) val schemaLocations: List<String>,
@DefaultValue("true") val schemaWiringValidationEnabled: Boolean,
@DefaultValue("false") val enableEntityFetcherCustomScalarParsing: Boolean,
/** Data loader properties.*/
@DefaultValue("false") val dataloaderTickerModeEnabled: Boolean
@DefaultValue("false") val enableEntityFetcherCustomScalarParsing: Boolean
) {

companion object {
const val PREFIX: String = "dgs.graphql"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2021 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.graphql.dgs.autoconfig

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import java.time.Duration

/**
* Configuration properties for DGS framework.
*/
@ConfigurationProperties(prefix = DgsDataloaderConfigurationProperties.DATALOADER_PREFIX)
@Suppress("ConfigurationProperties")
data class DgsDataloaderConfigurationProperties(
@DefaultValue("false") val tickerModeEnabled: Boolean,
@DefaultValue(DATALOADER_DEFAULT_SCHEDULE_DURATION) val scheduleDuration: Duration
) {
companion object {
const val DATALOADER_PREFIX: String = "dgs.graphql.dataloader"
const val DATALOADER_DEFAULT_SCHEDULE_DURATION = "10ms"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.springframework.aop.support.AopUtils
import org.springframework.beans.factory.NoSuchBeanDefinitionException
import org.springframework.context.ApplicationContext
import org.springframework.util.ReflectionUtils
import java.time.Duration
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.function.Supplier
Expand All @@ -50,6 +51,7 @@ class DgsDataLoaderProvider(
private val applicationContext: ApplicationContext,
private val dataLoaderOptionsProvider: DgsDataLoaderOptionsProvider = DefaultDataLoaderOptionsProvider(),
private val scheduledExecutorService: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor(),
private val scheduleDuration: Duration = Duration.ofMillis(10),
private val enableTickerMode: Boolean = false
) {

Expand All @@ -69,9 +71,7 @@ class DgsDataLoaderProvider(
fun <T> buildRegistryWithContextSupplier(contextSupplier: Supplier<T>): DataLoaderRegistry {
// We need to set the default predicate to 20ms and individually override with DISPATCH_ALWAYS or the custom dispatch predicate, if specified
// The data loader ends up applying the overall dispatch predicate when the custom dispatch predicate is not true otherwise.
val registry = ScheduledDataLoaderRegistry.newScheduledRegistry().scheduledExecutorService(scheduledExecutorService).tickerMode(enableTickerMode).dispatchPredicate(
DispatchPredicate.DISPATCH_NEVER
).build()
val registry = ScheduledDataLoaderRegistry.newScheduledRegistry().scheduledExecutorService(scheduledExecutorService).tickerMode(enableTickerMode).schedule(scheduleDuration).dispatchPredicate(DispatchPredicate.DISPATCH_NEVER).build()

val totalTime = measureTimeMillis {
val extensionProviders = applicationContext
Expand Down

0 comments on commit 620e4b6

Please sign in to comment.