Hotchocolate: Unable to have DataLoader properly batch requests

Created on 24 Apr 2020  路  9Comments  路  Source: ChilliCream/hotchocolate

Hello!

I have not been using Hot Chocolate for long, and just started playing with your implementation for the DataLoader. I am not sure whether what I'm reporting is a bug, or just me failing to grasp the proper usage of the DataLoader.

I am using BatchDataLoader in a simple resolver, like so:

public class Query
{
    private readonly IRepository repository;

    public Query(IRepository repository)
    {
        this.repository = repository;
    }

    public Task<Element> Elements(IResolverContext context, string id)
    {
        Task<Element> elementTask = context
            .BatchDataLoader<string, Element>("elementsByIdBatch", keys => this.repository.GetElements(keys))
            .LoadAsync(id);

        return elementTask;
    }
}

In Startup.cs, I have this to initialize the whole thing:

services.AddDataLoaderRegistry();

services.AddGraphQL(sp => SchemaBuilder.New()
    .AddQueryType<Query>()
    .Create());

I notice that my function this.repository.GetElements gets called multiple times, in fact as many times as there are keys. From what I understood of the DataLoader, I would have expected that it gets called only once, and that the information be obtained using the resulting Dictionary?

I feel like this is more about me not understanding the feature properly, rather than being an actual bug, since I haven't seen anyone else report this. So, I hope it's fine for me to ask this here! Let me know if there's any other information you need.

Thank you!

馃尪 green donut

Most helpful comment

Hi @vsylvestre,

Version 11.0 is planned for May.

All 9 comments

Are you on 10.* version?
Are you using ForceSerialExecution?

If so, you can find explaination in this slack thread.

Also you can drop DataLoaders using ORM with IQueryable support using UseSelection field middeware (blog post)

11 version should fix this issue click

@sergeyshaykhullin I was on version 10.4.2. I'm not using ForceSerialExecution. I also tried with 11.0.0-preview.127, but it still didn't work.

However, after doing some reading, I found that what I was probably looking for was a Global DataLoader. I'm having multiple queries sent from the client, and I'm looking to gather those under a single request to the DB.

Without changing anything to my resolver and adding the following line to my startup, it seems to work, but only once (will give details below):

services.AddSingleton<IDataLoaderRegistry, DataLoaderRegistry>();

By "once", I mean that the first "batch" of requests results in a single call to my GetElements method, as expected, but all subsequent batches end up in the following error:

An exception of type 'System.NullReferenceException' occurred in HotChocolate.Types.dll but was not handled in user code: 'Object reference not set to an instance of an object.'
   at HotChocolate.DataLoader.DataLoaderBatchOperation.RequestBuffered(IDataLoader sender, EventArgs eventArgs)
   at GreenDonut.DataLoaderBase`2.RaiseRequestBuffered()
   at GreenDonut.DataLoaderBase`2.LoadAsync(TKey key, CancellationToken cancellationToken)
   at GreenDonut.DataLoaderExtensions.LoadAsync[TKey,TValue](IDataLoader`2 dataLoader, TKey key)

I found that that was already reported here: https://github.com/ChilliCream/hotchocolate/issues/1571. But the workaround that's provided in this issue wouldn't really work in my case since I'm not working with a "class DataLoader". Would it be necessary that I create one? I see that there's a SlidingExpiration configuration option passed in the data loader of the linked example, so maybe that's something I would need to define?

Hi @vsylvestre

Sorry this issue fell somewhat below the radar.
You are right. Dataloaders by default are scoped. so they can but not have to group requests to the database (depends on your graph). Global dataloader is the way to go in your case.

I don't think we have any Global Dataloaders..

Currently @rstaib is rewriting the Dataloaders in V11. He is implementing the Dataloder Spec V2. I think the version 2 of the spec might help you a bit :)

Hi @PascalSenn,

Thank you for your answer. I was under the impression that the Global DataLoader was supported because of the documentation, but I can wait for the final V11 implementation if that's better. Is there an approximate timeframe for the official release?

I'm really interested in this feature, so let me know if there's anything I/we can do to help. 馃檪

Hi @vsylvestre,

Version 11.0 is planned for May.

Hi,

I have the exact problem as the OP. I've tried many times to make use of batch loader but everything seems to result in no batching taking place. Its at the point where this seems to be something so fundamental not working that I'm sure I'm just misunderstanding something. I don't have access to the Slack workspace so I can't follow every link above so maybe I'm missing something but I have attached an image demonstrating my issue.

It seems that calling LoadAsync() on the batched data loader immediately hits the SQL database with a single key, as opposed to deferring until other keys have been collected.

batch_loader

Any insights on where I'm going wrong would be much appreciated!

Ah! Works with the latest version 11 preview!

@RobTF are you use ForceSerialExecution?

I am closing this issue since we now allow to pool ef which solves the thread issues. Also with version 11 we more aggressively batch then with 10. Examples can be found here: https://github.com/michaelstaib/graphql-workshop

Was this page helpful?
0 / 5 - 0 ratings