Skip to content

Add documentation for Chained DataLoaders #196

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
69 changes: 69 additions & 0 deletions documentation/batching.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,72 @@ DataFetcher<?> dataFetcherThatCallsTheDataLoader = new DataFetcher<Object>() {
}
};
```

## Chained DataLoaders

The automatic dispatching of Chained DataLoaders is a new feature included in GraphQL Java 25.0 onwards. Before this version, DataLoaders in chains needed to be manually dispatched.

A Chained DataLoader is where one DataLoader depends on another, within the same DataFetcher.

For example in code:
```java
DataFetcher<CompletableFuture<Object>> df1 = env -> {
return env.getDataLoader("name").load("Key1").thenCompose(result -> {
return env.getDataLoader("email").load(result);
});
};
```

### How do I enable Chained DataLoaders?
You must opt-in to Chained DataLoaders via `GraphQLUnusualConfiguration.DataloaderConfig`, as this may change order of dispatching.

1. Set `enableDataLoaderChaining(true)` to enable Chained DataLoaders
2. Provide a `ScheduledExecutorService` to GraphQL Java, with method `delayedDataLoaderExecutorFactory` and a parameter that implements `DelayedDataLoaderDispatcherExecutorFactory`

For example, to set `enableDataLoaderChaining`:
```java
GraphQL graphQL = GraphQL.unusualConfiguration(graphqlContext)
.dataloaderConfig()
.enableDataLoaderChaining(true);
```

### What changed in GraphQL Java 25.0?
The DataFetcher in the example above, before version 25.0 would have caused execution to hang, because the second DataLoader ("email") was never dispatched.

Prior to version 25.0, users of GraphQL Java needed to manually dispatch DataLoaders to ensure execution completed. From version 25.0, the GraphQL Java engine will automatically dispatch Chained DataLoaders.

If you're looking for more examples, and the technical details, please see [our tests](https://github.com/graphql-java/graphql-java/blob/master/src/test/groovy/graphql/ChainedDataLoaderTest.groovy).

Note: The GraphQL Java engine can only optimally calculate DataLoader dispatches on a per-level basis. It does not calculate optimal DataLoader dispatching across different levels of an operation's field tree.

### A special case: Delayed DataLoaders

In a previous code snippet we demonstrated one DataLoader depending on another DataLoader.

Another special case is a "delayed" DataLoader, where a DataLoader depends on a slow async task instead. For example, here are two DataFetchers from [a test example](https://github.com/graphql-java/graphql-java/blob/master/src/test/groovy/graphql/ChainedDataLoaderTest.groovy):

```groovy
def fooDF = { env ->
return supplyAsync {
Thread.sleep(1000)
return "fooFirstValue"
}.thenCompose {
return env.getDataLoader("dl").load(it)
}
} as DataFetcher

def barDF = { env ->
return supplyAsync {
Thread.sleep(1000)
return "barFirstValue"
}.thenCompose {
return env.getDataLoader("dl").load(it)
}
} as DataFetcher
```

By opting in to Chained DataLoaders, GraphQL Java will also calculate when to dispatch "delayed" DataLoaders.

The default value for the time to wait for these "delayed" DataLoaders is 500,000ns (`DEFAULT_BATCH_WINDOW_NANO_SECONDS_DEFAULT`). If you like, you can configure your own batch window via the method `delayedDataLoaderBatchWindowSize` in `GraphQLUnusualConfiguration.DataloaderConfig`.

Note that the case, where one DataLoader depends on another DataLoader all within the same DataFetcher, is unaffected by this batch window configuration. This window configuration only changes how long to wait for the "delayed" DataLoader case, where a DataLoader depends on another async task.