Data loader does not batch invokes of a graphql query with custom batch scheduling function

Viewed 17

I'm trying to optimize DB queries using a data loader for my graphql query. The query accepts only one param (userId). Unfortunately, I can not send an array of ids from the frontend because it requires changing the architecture significantly. So as a temp solution I invoke the query one by one for each user and try to batch them on the backend.

How does it work now?

On the frontend I've enabled Apollo graphql batching. So, the frontend sends up to 10 queries to get user info at the same time. I've implemented a data loader on the backend using this batch scheduling as described in this section.

const userInfoLoader = new DataLoader<string, UserEntity>(
  (keys: readonly string[]) => this.userService.findByIds(keys as string[]),
  {
    batchScheduleFn: (batchFn) => setTimeout(batchFn, 30),
  }
);

// Then in the query resolver
const affectedUser = await loaders.userInfoLoader.load(userId);

I see that the loader successfully collects all user ids when the frontend sends a batch of getUserInfo queries in one POST request. But if it sends them as separate request the loader does not collect them (even if I increase timeout time) and do a separate DB query for each of them.

Using the logs I see that each separate query comes within 5 - 10 milliseconds after each other. So, I guess it should collect all ids from them but it's not.

UPD: Fixed. We need to make sure that the loader's instance is persistent. We create it once when a server starts, so we can use it across all requests. In another case we create a new instance of loader for each request from the frontend, so a loader from one request simply does not know about other requests. Also, don't forget to disable cache for such loaders to avoid uncontrolled usage of memory. https://github.com/graphql/dataloader#custom-cache

0 Answers
Related