Apollo-client: Memory leak when using Reactive variables in SSR setup on the server

Created on 2 Nov 2020  ·  1Comment  ·  Source: apollographql/apollo-client

Intended outcome:

Usage of reactive vars on the server-rendering shouldn't create a memory leak.

Actual outcome:

When an app, that uses reactive vars, is rendered on the server, it holds the query results in memory forever. Even though a new client, cache, and reactiveVar instances are created freshly for every request.
Probably because the references to reactive vars are held in a global context?

How to reproduce the issue:

We make use of the following function to create a new apollo client on every request to the serve:

export default function createCache() {
  const reactiveVars = {
    var1: makeVar({}),
    var2: makeVar({}),
    var2: makeVar({}),
  };

  return new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          field1() {
            return reactiveVars.var1();
          },
          field2() {
            return reactiveVars.var2();
          },
          field3() {
            return reactiveVars.var3();
          },
        },
      },
    },
  });
}

And we observed from heap-dumps that the cache data is held in the memory when we use the reactive-vars even after a GC.
And if we remove the usage of reactive vars, the memory recovers back to normal after the GC.

Screenshot of a sample object(one of tons of similar ones) that were in memory:
Screenshot 2020-11-02 at 1 35 53 PM

Versions

System:
    OS: macOS 10.15.7
  Binaries:
    Node: 12.13.0 - ~/.nvm/versions/node/v12.13.0/bin/node
    Yarn: 1.18.0 - /usr/local/bin/yarn
    npm: 6.12.0 - ~/.nvm/versions/node/v12.13.0/bin/npm
  Browsers:
    Chrome: 85.0.4183.121
    Edge: 81.0.416.68
    Firefox: 78.3.1
    Safari: 14.0
npmPackages:
    @apollo/client: ^3.2.5 => 3.2.5 
🐞 bug 💸 caching 🛫 in-progress 🧩 implementation-detail

Most helpful comment

@manojVivek Thanks for opening this issue! I can see what the problem is, and how to fix it, though I suspect any possible solution to this problem will depend on you explicitly calling client.stop() after you finish using client during SSR, which ultimately cancels all cache watches, which is an event we can use to remove the cache from the caches set for any reactive variables currently holding references to the cache. We're not currently hooking into that event (hence this bug), but I think it should be straightforward to set that up.

>All comments

@manojVivek Thanks for opening this issue! I can see what the problem is, and how to fix it, though I suspect any possible solution to this problem will depend on you explicitly calling client.stop() after you finish using client during SSR, which ultimately cancels all cache watches, which is an event we can use to remove the cache from the caches set for any reactive variables currently holding references to the cache. We're not currently hooking into that event (hence this bug), but I think it should be straightforward to set that up.

Was this page helpful?
0 / 5 - 0 ratings