Dataloader bug (JavaEE+MyBatis)
iteaky opened this issue · 0 comments
I have graphql in my production, and it's forbidden to share the code. I'm using graphql-java-servlet, as ORM I use MyBatis.
com.graphql-java-kickstart graphql-java-servlet 9.2.0 After enabling BatchLoading I found that graphQL DataLoader is confuses places of batch-requested Entities. Also it's easy to check if take a look in futureCacheMap, you will find that Key(Id) And Value(Entity) have different id's.After debbuging, I did't found the way how graphQL resolve Entites after batchLoading (1000 psc). So I decided that I should have some ordering, so I implemented it, but It didn't resolve the issue.
For example: I Have Parent.class who Have Childs inside.
class Parent {
private Long id;
private List<Long> childsIds;
}
I have ChildDataloader
private BatchLoader<Long, Child> buildBatchLoader() {
return list -> > CompletableFuture.supplyAsync(() ->
childService.findByIds(list));
}
private DataLoader<Long, Child> buildDataLoader(BatchLoader batchLoader) {
DataLoaderOptions options = DataLoaderOptions.newOptions();
options.setMaxBatchSize(1000);
return new DataLoader<Long, Child>(batchLoader, options);
}
}
I have ChildsFetcher where I call dataLoader.loadMany()
public class ChildsFetcher implements DataFetcher<CompletableFuture<List<Child>>>{
private static final String PK_FIELD_NAME = "childsIds";
@Override
public CompletableFuture<List<LoadDefinitionDTO>> get(DataFetchingEnvironment environment) {
GraphQLContext context = environment.getContext();
DataLoaderRegistry dataLoaderRegistry = context.getDataLoaderRegistry().orElseThrow(
() -> new DalException("there was no dataLoaderRegistry in context", Response.Status.INTERNAL_SERVER_ERROR)
);
List<Long> childsIds = getParentFieldValue(environment, LOAD_DEFINITION_PK_FIELD_NAME, List.class);
DataLoader<Long, Child> childDataLoader = dataLoaderRegistry.getDataLoader("childDataLoader");
return childDataLoader.loadMany(childsIds)
}
}
For Example I have 2 Parents with 3 child each.
parents: [
{
"id": 1
"childIds": {1,3,5}
},
{
"id": 2
"childIds": {2,4,6}
}
As a result in fetcher I will have 2 requests:
-
childDataLoader.loadMany({1,3,5})
-
childDataLoader.loadMany({2,4,6})
But in Dataloader it will be only one (as expected), but look at the order of the ids (I cannot take control on it):
childService.findByIds({1,2,3,4,5,6})
And in output I will receive:
"data": {
"parents": [
{
"id": 1,
"childs": [
{
"id": 1,
},
{
"id": 2,
},
{
"id": 3,
}
},
{
"id": 2,
"childs": [
{
"id": 4,
},
{
"id": 5,
},
{
"id": 6,
}
}
]
}