Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Garbage collection not removing references edited by writeFragment #10307

Open
patrikniebur opened this issue Nov 22, 2022 · 3 comments
Open
Labels

Comments

@patrikniebur
Copy link

Intended outcome:

When references are not reachable via normal query, running cache.gc() will remove the objects from cache regardless of the reference being edited using writeFragment

Actual outcome:

References that were edited using writeFragment are not deleted even though they are otherwise unreachable via normal query calling cache.gc() will not remove them.

How to reproduce the issue:

Reproduced sandbox

  1. Write couple of objects into the cache using writeQuery
  2. Edit one of them using writeFragment
  3. Remove references from query by overwriting them with an empty array
  4. Run garbage collection
  5. Observe that reference that has been edited using writeFragment has not been removed.

Versions

  System:
    OS: macOS 13.0.1
  Binaries:
    Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node
    npm: 8.1.0 - ~/.nvm/versions/node/v16.13.0/bin/npm
  Browsers:
    Chrome: 107.0.5304.110
    Firefox: 104.0.1
    Safari: 16.1
  "dependencies": {
    "@apollo/client": "3.7.1",
    "graphql": "16.6.0",
  }
@patrikniebur
Copy link
Author

Using writeFragment adds new root __META with extraRootIds property containing reference to edited object. This explains why calling gc does not delete the object but it seem to be unexpected side-effect.

@hwride
Copy link

hwride commented Jul 3, 2023

The default mutation example in the client docs suggests using cache.writeFragment inside update to get a reference to an object so you can do things like manually update lists in the cache, see https://www.apollographql.com/docs/react/data/mutations/#the-update-function:

update(cache, { data: { addTodo } }) {
  cache.modify({
    fields: {
      todos(existingTodos = []) {
        const newTodoRef = cache.writeFragment({
          data: addTodo,
          fragment: gql`
              fragment NewTodo on Todo {
                  id
                  type
              }
          `
        });
        return [...existingTodos, newTodoRef];
      }
    }
  });
}

This seems to mean that if we use the default recommended example for these kind of updates, those objects will be always immune to garbage collection. I found this when trying to expand on the getting started example to remove things and then found they didn't disappear when running cache.gc(). I wonder if this is worth calling out in the docs?

@nathanjcochran
Copy link

nathanjcochran commented Dec 11, 2024

I ran into this too. One workaround is to call cache.release() (see docs) after calling cache.writeFragment(), which effectively removes the reference from __META.extraRootIds and allows the object to be garbage collected if it's no longer reachable.

Using @hwride's code above as an example:

update(cache, { data: { addTodo } }) {
  cache.modify({
    fields: {
      todos(existingTodos = []) {
        const newTodoRef = cache.writeFragment({
          data: addTodo,
          fragment: gql`
              fragment NewTodo on Todo {
                  id
                  type
              }
          `
        });
        
        if (cache instanceof InMemoryCache && newTodoRef) {
          const newTodoId = cache.identify(newTodoRef);
          if (newTodoId) {
            apolloClient.cache.release(newTodoId);
          }
        }
        
        return [...existingTodos, newTodoRef];
      }
    }
  });
}

Note that cache.release() is only available on InMemoryCache (see #7563), which is the reason for the cache instanceof InMemoryCache check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants