apollo-datasource-http icon indicating copy to clipboard operation
apollo-datasource-http copied to clipboard

[Discussion] How to dedupe concurrent memoizable requests?

Open llc1123 opened this issue 2 years ago • 5 comments

The Problem

Concurrent requests usually happen:

  • When resolving multiple fields of the same object.
  • When one object appears in multiple locations of a query.

Multiple requests occur and these requests should be deduped if marked as memoizable.

Examples

const resolvers: Resolvers = {
  UserInfo: {
    name: async ({ mid }, _, { dataSources }) =>
      (await dataSources.example.getUserInfo(mid)).name,
    gender: async ({ mid }, _, { dataSources }) =>
      (await dataSources.example.getUserInfo(mid)).gender,
    avatar: async ({ mid }, _, { dataSources }) =>
      (await dataSources.example.getUserInfo(mid)).avatar,
  },
}
query Users {
  currentUser {
    mid
    name
    avatar
  }
  userInfo(mid: 123) {
    name
    avatar
  }
}

My suggestion

We should use a lazy loader (like graphql/dataloader but much simpler as we don't need batching and caching).

See #29 for my rough workaround.

Minor question

How to define response.memoize if the response is from deduped result?

llc1123 avatar Apr 07 '22 16:04 llc1123

Why is it not possible to just memoize the original promise? It seems what needs to be done is that the response Promise needs to be created and inserted into the memoization cache Prior to request execution.

That way, any subsequent queries checking the memo cache will fetch the promise and wait for the original execution to complete (and then likewise 'share' the response).

bradleymorris avatar Apr 08 '22 13:04 bradleymorris

I don't think storing the promise in cache is a good idea. How do you deal with promise rejection?

@StarpTech What do you think?

llc1123 avatar Apr 12 '22 11:04 llc1123

I don't think I see the problem you're alluding to in regards to promise rejection. The memoization store is different from the 'proper' cache and nothing is serialized or written to disk with the dedicated alloc/quicklru memoization cache, as far as I am aware.

So if the promise is rejected, any executions awaiting the promise will be notified as they typically would be, even if they are late arrivers and await promise fulfillment after the promise was either fulfilled or rejected.

I could be over-simplifying something, here, but I think that the Apollo out-of-box REST data source might do something similar to avoid this problem as well.

bradleymorris avatar Apr 12 '22 11:04 bradleymorris

I have submitted a PR #37 memoizing promises and it looks good.

llc1123 avatar Apr 17 '22 12:04 llc1123

@llc1123 Thank you for your time and effort on this. Hopefully it gets merged and released soon!

bradleymorris avatar Jun 30 '22 15:06 bradleymorris