I've been looking into using a DataLoader in Django to optimise Graphene resolvers. I have been having trouble finding a working example of this as it requires multi threading. Based on what I can tell, there is no longer a way to specify executors in the latest versions of GraphQL in python. Does anyone have a working setup as an example?
I was following the example below, and everytime I use async
for my resolvers, I get:
RuntimeError: There is no current event loop in thread 'ThreadPoolExecutor-1_0'.
Which I think makes sense because GraphQL is using a sync
executor by default (I stand corrected). I got this example from: https://docs.graphene-python.org/en/latest/execution/dataloader/
Source code:
dataloaders.py
from dataloader import DataLoader
class UserDataLoader(DataLoader):
async def batch_load_fn(self, keys):
pass
class PostDataLoader(DataLoader):
async def batch_load_fn(self, keys):
pass
graphql.py
import graphene
from graphene_django.types import DjangoObjectType
from .models import User, Post
from .dataloaders import UserDataLoader, PostDataLoader
class UserType(DjangoObjectType):
class Meta:
model = User
class PostType(DjangoObjectType):
class Meta:
model = Post
class Query(graphene.ObjectType):
user = graphene.Field(UserType, id=graphene.Int())
post = graphene.Field(PostType, id=graphene.Int())
async def resolve_user(self, info, id):
user_data_loader = UserDataLoader(info.context)
return await user_data_loader.load(id)
async def resolve_post(self, info, id):
post_data_loader = PostDataLoader(info.context)
return await post_data_loader.load(id)
schema = graphene.Schema(query=Query)
view.py
from graphene import BatchingExecutor # <- Does not exist in the library anymore
from graphene_django.views import GraphQLView
class NewDataLoaderGraphQLView(GraphQLView):
executor = BatchingExecutor()
def get_context(self, request):
# Create new data loader instances for each request
context = super().get_context(request)
context.user_data_loader = UserDataLoader(context)
context.post_data_loader = PostDataLoader(context)
return context
urls.py
from django.urls import path
from .views import NewDataLoaderGraphQLView
urlpatterns = [
path("graphql/", NewDataLoaderGraphQLView.as_view(graphiql=True)),
]
I'm running this using
./manage.py runserver 0.0.0.0:80
Note: This is not production code because I'm still testing this.
APPROACH ABANDONED
At this time, there are a lot of inconsistencies in concurrency support for Django + GraphQL. At least I didn't have any luck finding anything reliable. The closest I came was the following library which I am trialing. https://github.com/jkimbo/graphql-sync-dataloaders
batch_function
– Oestriol