ParabolInc / parabol

Free online agile retrospective meeting tool
https://www.parabol.co/
Other
1.91k stars 331 forks source link

dataloader and graphql subscriptions #1218

Closed mattkrick closed 6 years ago

mattkrick commented 7 years ago

dataloader is usually used on a per-execution basis (ie 1 call to a graphql execute). that's pretty useless on subscriptions. instead, subscriptions should span across users on a per-channel basis.

so, the only way i think we can do this is by mutating the context passed into a mutation.

mattkrick commented 7 years ago

closing because there is no straightforward path to doing this. the problem is we need to create and clear the cache from within a graphql resolve call. we can create it by seeing if it exists, and then creating it if it doesn't. however, if a mutation & a subscription call have payloads that share the same GraphQLObject, then we're not guaranteed we'll get everything we need in the source. a good example if the JoinIntegrationPayload. we want to fulfill teamMember, and we can do that by supplying teamMemberId to the source. otherwise, we'll have to look up the teammember based on the globalId, which means 1 more lookup. not the end of the world, since a dataloader could save us more than 1 load in the long run. however, when to destroy is a tricky one. we'd like to destroy after all the subscriptions have run. so, we could set a counter == subs.length & then after each resolve gets called, we subsLen--. however, that's difficult because it's all async, so a mutation might slip in the middle & then we'd clear the cache too soon. we could tweak the pubsub to add a onLastSub callback that runs after before the last sub gets called. that callback would have to mutate the context saying something like channelName: 'lastCall'. then, that resolve function would need to know the channel name it's working for, if any. to do that, we'd have to pass in channelName in the payload so it shows up in source of the resolve function. then, if lastCall is true, we know we can clear it.

mattkrick commented 7 years ago

another issue: ideally, the mutation could share the cached value (or at least set it, since it'll be guaranteed to run first). however, there is no easy way to determine that subscriptions will come after the mutation. so, we can't just store it in the same place like we would a subscription, because if a sub never comes, then it'll just live there forever. the only decent way around this is to build a TTL into it.

mattkrick commented 7 years ago

We finally have some cases where this could be beneficial (get the teamMember name for every archived project). for epic 7 it'll be comically inefficient, which will motivate us to do it right for epic 8

mattkrick commented 7 years ago

well my brain hurts, but i figured out how to do this w/o any changes to graphql:

we could approach this 2 ways:

I opted for the 2nd solution. Here's how it's implemented:

mattkrick commented 7 years ago

Considerations:

mattkrick commented 6 years ago

solved, implemented in projets-to-relay