question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Consider supporting promise-based dataloaders in v3

See original GitHub issue

I know graphql-core dropped support for promises, but the author seems to think promise-support can be added via hooks like middleware and execution context (see response to my identical issue in https://github.com/graphql-python/graphql-core/issues/148).

Since most people using syrusakbary’s promise library are probably already graphene users, if anyone is going to help make graphql-core 3 and promises play together, it makes sense for that to be done in graphene.

Why not just use async?

I think I have a decent use-case for non-async, promise-based resolution. Async is nice and all, and having a standard is great, but many of us are just using dataloaders as an execution pattern, not because we actually have async data-sources. Moving everything to run in async environment can have consequences.

We are calling the django ORM from our dataloaders. Because django 3.0 forces us to isolate ORM calls and wrap them in sync_to_async, we stuck with promise based dataloaders for syntactic reasons. Examples below:

What we’d like to do, but django doesn’t allow

class MyDataLoader(...):
    async def batch_load(self, ids):
        data_from_other_loader = await other_loader.load_many(ids)
      	data_from_orm = MyModel.objects.filter(id__in=ids) # error! can't call django ORM from async context. 
        # return processed combination of orm/loader data

What django would like us to do

class MyDataLoader(...):
    async def batch_load(self, ids):
        data_from_other_loader = await other_loader.load_many(ids)
        data_from_orm = await get_orm_data()
        # return processed combination of orm/loader data
    
@sync_to_async
def get_orm_data(ids):
    return MyModel.objects.filter(id__in=ids)

What we settled on instead (use generator-syntax around promises)

class MyDataLoader(...):
    def batch_load(self,ids):
        data_from_other_loader = yield other_loader.load_many(ids)
        data_from_orm = MyModel.objects.filter(id__in=ids)
        # return processed combination of orm/loader data

A simple generator_function_to_promise is used as part of dataloaders, as well as a middleware that converts generators returned from resolvers into promises. I have hundreds of dataloaders following this pattern. I don’t want to be stuck isolating all the ORM calls as per django’s recommendations. That would be noisy and decrease legibility.

It seems there may be other issues around using async dataloaders with connections. Admittedly that problem sounds more easily surmountable and wouldn’t require supporting promises.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:21 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
jkimbocommented, Sep 23, 2022

So after investigating lots of other options for supporting DataLoaders with Django I’ve come to the conclusion that the best approach is by implementing a custom execution context class in graphql-core to handle “deferred/future” values. I’ve proposed this change here https://github.com/graphql-python/graphql-core/pull/155 but until we can get it merged into graphql-core I’ve published a library to let you integrate it with Graphene (v3) now: https://github.com/jkimbo/graphql-sync-dataloaders

@superlevure @felixmeziere @AlexCLeduc I hope this is able to help you.

1reaction
AlexCLeduccommented, Oct 21, 2022

@ericls yes I’m in that Ottawa haha. Glad to hear fellowapp is still using promises, makes me feel less crazy 😄

If anyone is interested in the generator syntactic sugar I described in the OP, it’s quite simple to implement. Not having to rewrite it is a motivation to keep using the old promise library It’s now its own package

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to return two variables from promise DataLoader?
Try using asyncio Dataloaders instead of Promise based dataloaders as promises were deprecated in graphene V3 check here.
Read more >
Complete Guide to the DataLoader Class in PyTorch
This post covers the PyTorch dataloader class. We'll show how to load built-in and custom datasets in PyTorch, plus how to transform and...
Read more >
Using Express.js Routes for Promise-based Error Handling
Find out how to enable promise-based route code and centralize both error ... Here we create an Express.js app and add some basic...
Read more >
Datasets & DataLoaders - PyTorch
Dataset stores the samples and their corresponding labels, and DataLoader ... 1267326.31it/s] 4%|3 | 950272/26421880 [00:00<00:11, 2271953.24it/s] 7%|7 ...
Read more >
3 Promise-based Http Clients to use in NodeJS | by DLT Labs
So I don't think there is any need to rewrite this code using async/await. 3) Superagent. This module also supports sending requests through...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found