Skip to content

Cache Sharing Issue with Concurrent Calls in SSR #2357

Open
@arsenasatryan

Description

@arsenasatryan

Describe the bug

When using the documentation snippet for Apollo-Angular, concurrent requests lead to cache sharing issues. Instead of each request receiving its own data, one request receives a merged response from multiple pages while another receives no data. This occurs in an SSR setup when onSerialize extracts and resets the cache, potentially due to a shared InMemoryCache instance across requests.


To Reproduce

Steps to reproduce the behavior:

  1. Use the following Apollo configuration (taken from the documentation):

    import { provideApollo } from 'apollo-angular';
    import { HttpLink } from 'apollo-angular/http';
    import { provideHttpClient } from '@angular/common/http';
    import {
      ApplicationConfig,
      inject,
      InjectionToken,
      makeStateKey,
      TransferState,
    } from '@angular/core';
    import { InMemoryCache, NormalizedCacheObject } from '@apollo/client/core';
     
    const MY_APOLLO_CACHE = new InjectionToken<InMemoryCache>('apollo-cache');
    const STATE_KEY = makeStateKey<NormalizedCacheObject>('apollo.state');
     
    export const appConfig: ApplicationConfig = {
      providers: [
        provideHttpClient(),
        { provide: MY_APOLLO_CACHE, useValue: new InMemoryCache() },
        provideApollo(() => {
          const httpLink = inject(HttpLink);
          const cache = inject(MY_APOLLO_CACHE);
     
          const transferState = inject(TransferState);
          const isBrowser = transferState.hasKey(STATE_KEY);
          if (isBrowser) {
            const state = transferState.get(STATE_KEY, {});
            cache.restore(state);
          } else {
            transferState.onSerialize(STATE_KEY, () => {
              const result = cache.extract();
              // Reset cache after extraction to avoid sharing between requests
              cache.reset();
              return result;
            });
          }
     
          return {
            link: httpLink.create({ uri: '/graphql' }),
            cache: cache,
          };
        }),
      ],
    };
  2. Make multiple concurrent GraphQL requests from different pages. For example you can open 2 different pages, run the angular in development mode and change something in the code (enter or console.log) so it reloads both of the pages.

  3. Observe that one page contains a merged response from multiple requests, while another page receives no data.


Expected behavior

Each request should have an isolated cache instance to prevent data leakage between concurrent SSR requests.


Environment

Angular version: 17-19
all respective major versions of graphql and apollo-angular

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions