Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dataloader improvements #1720

Merged
merged 3 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading