graphene
graphene copied to clipboard
How are DataLoader promises deferred so that batching can occur?
I'm using SyncExecutor
from graphql-core
and ImmediateScheduler
from the promise
library with graphene
v2.1.8. My understanding is that these should synchronously and immediately execute any promises when they are created. If I use a dataloader outside of graphene resolvers, I see evidence of this immediate execution:
from promise import Promise
from promise.dataloader import DataLoader
def batch_load_fn(keys):
print('Keys:', keys)
return Promise.resolve(keys)
loader = DataLoader(batch_load_fn=batch_load_fn)
loader.load_many([1, 2, 3])
loader.load(4)
loader.load(5)
loader.load(6)
outputs:
Keys: [1]
Keys: [2]
Keys: [3]
Keys: [4]
Keys: [5]
Keys: [6]
The batch_load_fn
is called individually for each key with no batching. When I run the same code inside of a graphene resolver, I get
Keys: [1, 2, 3, 4, 5, 6]
which indicates that the promises aren't executing immediately and batching does happen. This is obviously desirable, and the point of using dataloaders in the first place, but I'm having trouble understanding the mechanism by which it is happening.
What is graphene
or graphql-core
doing to prevent the immediate synchronous execution of these promises so that dataloader batching can occur?
Was there any resolution for this issue?
I realized my issue was that my dataloader was being re-initialised in the middleware every time a new resolver was called. Used this to resolve that issue and that worked
@sangaline I ran into similar problem recently and it seems if we use the dataloader outside of graphene resolvers, we need to wrap the operations inside a function, and then chain it to a promise if we want the batch to work properly (called once with all arguments instead of individually with each argument). Something like this worked for me:
def fn(arg):
loader = DataLoader(batch_load_fn=batch_load_fn)
loader.load_many([1, 2, 3])
loader.load(4)
loader.load(5)
loader.load(6)
Promise.resolve(None).then(fn)