Skip to content
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
22 changes: 16 additions & 6 deletions src/jmh/java/performance/DataLoaderPerformance.java
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,23 @@ public Pet(String id, String name, String ownerId, List<String> friendsIds) {
static BatchLoader<String, Owner> ownerBatchLoader = list -> {
List<Owner> collect = list.stream().map(key -> {
Owner owner = owners.get(key);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return owner;
}).collect(Collectors.toList());
return CompletableFuture.completedFuture(collect);
};
static BatchLoader<String, Pet> petBatchLoader = list -> {
List<Pet> collect = list.stream().map(key -> {
Pet owner = pets.get(key);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return owner;
}).collect(Collectors.toList());
return CompletableFuture.completedFuture(collect);
Expand Down Expand Up @@ -532,20 +542,20 @@ public void setup() {
});
DataFetcher petsDf = (env -> {
Owner owner = env.getSource();
return env.getDataLoader(petDLName).loadMany((List) owner.petIds)
.thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
return env.getDataLoader(petDLName).loadMany((List) owner.petIds);
// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
});

DataFetcher petFriendsDF = (env -> {
Pet pet = env.getSource();
return env.getDataLoader(petDLName).loadMany((List) pet.friendsIds)
.thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
return env.getDataLoader(petDLName).loadMany((List) pet.friendsIds);
// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
});

DataFetcher petOwnerDF = (env -> {
Pet pet = env.getSource();
return env.getDataLoader(ownerDLName).load(pet.ownerId)
.thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
return env.getDataLoader(ownerDLName).load(pet.ownerId);
// .thenCompose((result) -> CompletableFuture.supplyAsync(() -> null).thenApply((__) -> result));
});


Expand Down
18 changes: 17 additions & 1 deletion src/main/java/graphql/GraphQLUnusualConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import static graphql.Assert.assertNotNull;
import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING;
import static graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING;

/**
* This allows you to control "unusual" aspects of the GraphQL system
Expand Down Expand Up @@ -344,12 +345,16 @@ private DataloaderConfig(GraphQLContextConfiguration contextConfig) {
}

/**
* @return true if @defer and @stream behaviour is enabled for this execution.
* returns true if chained data loader dispatching is enabled
*/
public boolean isDataLoaderChainingEnabled() {
return contextConfig.getBoolean(ENABLE_DATA_LOADER_CHAINING);
}

public boolean isDataLoaderExhaustedDispatchingEnabled() {
return contextConfig.get(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING);
}

/**
* Enables the ability that chained DataLoaders are dispatched automatically.
*/
Expand All @@ -359,6 +364,17 @@ public DataloaderConfig enableDataLoaderChaining(boolean enable) {
return this;
}

/**
* Enables a dispatching strategy that will dispatch as long as there is no
* other data fetcher or batch loader running.
*/
@ExperimentalApi
public DataloaderConfig enableDataLoaderExhaustedDispatching(boolean enable) {
contextConfig.put(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, enable);
return this;
}


}

public static class ResponseMapFactoryConfig extends BaseContextConfig {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/graphql/execution/AsyncExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ public CompletableFuture<ExecutionResult> execute(ExecutionContext executionCont
DeferredExecutionSupport deferredExecutionSupport = createDeferredExecutionSupport(executionContext, parameters);

dataLoaderDispatcherStrategy.executionStrategy(executionContext, parameters, deferredExecutionSupport.getNonDeferredFieldNames(fieldNames).size());

Async.CombinedBuilder<FieldValueInfo> futures = getAsyncFieldValueInfo(executionContext, parameters, deferredExecutionSupport);
dataLoaderDispatcherStrategy.finishedFetching(executionContext, parameters);


CompletableFuture<ExecutionResult> overallResult = new CompletableFuture<>();
executionStrategyCtx.onDispatched();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private Object resolveSerialField(ExecutionContext executionContext,
dataLoaderDispatcherStrategy.executionSerialStrategy(executionContext, newParameters);

Object fieldWithInfo = resolveFieldWithInfo(executionContext, newParameters);
dataLoaderDispatcherStrategy.finishedFetching(executionContext, newParameters);
if (fieldWithInfo instanceof CompletableFuture) {
//noinspection unchecked
return ((CompletableFuture<FieldValueInfo>) fieldWithInfo).thenCompose(fvi -> {
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/graphql/execution/DataLoaderDispatchStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,20 @@ default void newSubscriptionExecution(AlternativeCallContext alternativeCallCont
default void subscriptionEventCompletionDone(AlternativeCallContext alternativeCallContext) {

}

default void finishedFetching(ExecutionContext executionContext, ExecutionStrategyParameters newParameters) {

}

default void deferFieldFetched(ExecutionStrategyParameters executionStrategyParameters) {

}

default void startComplete(ExecutionStrategyParameters parameters) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc would be nice


}

default void stopComplete(ExecutionStrategyParameters parameters) {

}
}
9 changes: 9 additions & 0 deletions src/main/java/graphql/execution/Execution.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
import graphql.GraphQL;
import graphql.GraphQLContext;
import graphql.GraphQLError;
import graphql.GraphQLException;
import graphql.Internal;
import graphql.Profiler;
import graphql.execution.incremental.IncrementalCallState;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.InstrumentationState;
import graphql.execution.instrumentation.dataloader.DataLoaderDispatchingContextKeys;
import graphql.execution.instrumentation.dataloader.ExhaustedDataLoaderDispatchStrategy;
import graphql.execution.instrumentation.dataloader.PerLevelDataLoaderDispatchStrategy;
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters;
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters;
Expand Down Expand Up @@ -262,6 +265,12 @@ private DataLoaderDispatchStrategy createDataLoaderDispatchStrategy(ExecutionCon
if (executionContext.getDataLoaderRegistry() == EMPTY_DATALOADER_REGISTRY || doNotAutomaticallyDispatchDataLoader) {
return DataLoaderDispatchStrategy.NO_OP;
}
if (executionContext.getGraphQLContext().getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, false)) {
if (executionContext.getGraphQLContext().getBoolean(DataLoaderDispatchingContextKeys.ENABLE_DATA_LOADER_CHAINING, false)) {
throw new GraphQLException("enabling data loader chaining and exhausted dispatching at the same time ambiguous");
}
return new ExhaustedDataLoaderDispatchStrategy(executionContext);
}
return new PerLevelDataLoaderDispatchStrategy(executionContext);
}

Expand Down
8 changes: 6 additions & 2 deletions src/main/java/graphql/execution/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,12 @@ protected Object resolveFieldWithInfo(ExecutionContext executionContext, Executi
Object fetchedValueObj = fetchField(executionContext, parameters);
if (fetchedValueObj instanceof CompletableFuture) {
CompletableFuture<Object> fetchFieldFuture = (CompletableFuture<Object>) fetchedValueObj;
CompletableFuture<FieldValueInfo> result = fetchFieldFuture.thenApply((fetchedValue) ->
completeField(fieldDef, executionContext, parameters, fetchedValue));
CompletableFuture<FieldValueInfo> result = fetchFieldFuture.thenApply((fetchedValue) -> {
executionContext.getDataLoaderDispatcherStrategy().startComplete(parameters);
FieldValueInfo completeFieldResult = completeField(fieldDef, executionContext, parameters, fetchedValue);
executionContext.getDataLoaderDispatcherStrategy().stopComplete(parameters);
return completeFieldResult;
});

fieldCtx.onDispatched();
result.whenComplete(fieldCtx::onCompleted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ private Supplier<CompletableFuture<DeferredFragmentCall.FieldWithExecutionResult
InstrumentationContext<Object> deferredFieldCtx = nonNullCtx(instrumentation.beginDeferredField(fieldParameters, executionContext.getInstrumentationState()));

CompletableFuture<FieldValueInfo> fieldValueResult = resolveFieldWithInfoFn.apply(this.executionContext, executionStrategyParameters);
executionContext.getDataLoaderDispatcherStrategy().deferFieldFetched(executionStrategyParameters);


deferredFieldCtx.onDispatched();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ private DataLoaderDispatchingContextKeys() {
public static final String ENABLE_DATA_LOADER_CHAINING = "__GJ_enable_data_loader_chaining";


/**
* Enabled a different dispatching strategy that mimics the JS event loop based one:
* DataLoader will be dispatched as soon as there is no data fetcher or batch loader currently running.
*
*/
public static final String ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING = "__GJ_enable_data_loader_exhausted_dispatching";

/**
* Enables the ability that chained DataLoaders are dispatched automatically.
*
Expand All @@ -34,5 +41,14 @@ public static void setEnableDataLoaderChaining(GraphQLContext graphQLContext, bo
graphQLContext.put(ENABLE_DATA_LOADER_CHAINING, enabled);
}

/**
* Enables the ability that chained DataLoaders are dispatched automatically.
*
* @param graphQLContext
*/
public static void setEnableDataLoaderExhaustedDispatching(GraphQLContext graphQLContext, boolean enabled) {
graphQLContext.put(ENABLE_DATA_LOADER_EXHAUSTED_DISPATCHING, enabled);
}


}
Loading