title: AWS AppSync query returns cached response even when offline is disabled
body: <p>I have a fairly simple node app using AWS AppSync. I am able to run queries and mutations successfully but I've recently found that if I run a query twice I get the same response - even when I know that the back-end data has changed. In this particular case the query is backed by a lambda and in digging into it I've discovered that the query doesn't seem to be sent out on the network because the lambda is not triggered each time the query runs - just the first time. If I use the console to simulate my query then everything runs fine. If I restart my app then the first time a query runs it works fine but successive queries again just return the same value each time.</p>
  
  <p>Here are some part of my code:</p>
  
  <pre><code>  client.query({
      query: gql`
      query GetAbc($cId: String!) {
        getAbc(cId: $cId) {
          id
          name
          cs
        }
      }`,
      options: {
        fetchPolicy: 'no-cache'
      },
      variables: {
        cid: event.cid
      }
    })
      .then((data) =&gt; {
        // same data every time
      })
  </code></pre>
  
  <p><strong>Edit</strong>: trying other fetch policies like <code>network-only</code> makes no visible difference.</p>
  
  <p>Here is how I set up the client, not super clean but it seems to work:</p>
  
  <pre><code>const makeAWSAppSyncClient = (credentials) =&gt; {
    return Promise.resolve(
      new AWSAppSyncClient({
        url: 'lalala',
        region: 'us-west-2',
        auth: {
          type: 'AWS_IAM',
          credentials: () =&gt; {
            return credentials
          }
        },
        disableOffline: true
      })
    )
  }
  
  getRemoteCredentials()
    .then((credentials) =&gt; {
      return makeAWSAppSyncClient(credentials)
    })
    .then((client) =&gt; {
      return client.hydrated()
    })
    .then((client) =&gt; {
      // client is good to use
    })
  </code></pre>
  
  <p><code>getRemoteCredentials</code> is a method to turn an IoT authentication into normal IAM credentials which can be used with other AWS SDKs. This is working (because I wouldn't get as far as I do if not).</p>
  
  <p>My issue seems very similar to this one <a href="https://stackoverflow.com/questions/50099028/graphql-query-runs-sucessfully-one-time-and-fails-to-run-again-using-apollo-and?rq=1">GraphQL Query Runs Sucessfully One Time and Fails To Run Again using Apollo and AWS AppSync</a>; I'm running in a node environment (rather than react) but it is essentially the same issue.</p>
  
  <hr>
  
  <p>I don't think this is relevant but for completeness I should mention I have tried both with and without the setup code from the docs. This appears to make no difference (except annoying logging, see below) but here it is:</p>
  
  <pre><code>global.WebSocket = require('ws')
  global.window = global.window || {
    setTimeout: setTimeout,
    clearTimeout: clearTimeout,
    WebSocket: global.WebSocket,
    ArrayBuffer: global.ArrayBuffer,
    addEventListener: function () { },
    navigator: { onLine: true }
  }
  
  global.localStorage = {
    store: {},
    getItem: function (key) {
      return this.store[key]
    },
    setItem: function (key, value) {
      this.store[key] = value
    },
    removeItem: function (key) {
      delete this.store[key]
    }
  };
  require('es6-promise').polyfill()
  require('isomorphic-fetch')
  </code></pre>
  
  <p>This is taken from: <a href="https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-javascript.html" rel="noreferrer">https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-javascript.html</a></p>
  
  <p>With this code and without <code>offlineDisabled: true</code> in the client setup I see this line spewed continuously on the console:</p>
  
  <blockquote>
    <p>redux-persist asyncLocalStorage requires a global localStorage object.
    Either use a different storage backend or if this is a universal redux
    application you probably should conditionally persist like so:
    <a href="https://gist.github.com/rt2zz/ac9eb396793f95ff3c3b" rel="noreferrer">https://gist.github.com/rt2zz/ac9eb396793f95ff3c3b</a></p>
  </blockquote>
  
  <p>This makes no apparent difference to this issue however.</p>
  
  <hr>
  
  <p><strong>Update</strong>: my dependencies from package.json, I have upgraded these during testing so my yarn.lock contains more recent revisions than listed here. Nevertheless: <a href="https://gist.github.com/macbutch/a319a2a7059adc3f68b9f9627598a8ca" rel="noreferrer">https://gist.github.com/macbutch/a319a2a7059adc3f68b9f9627598a8ca</a></p>
  
  <p><strong>Update #2</strong>: I have also confirmed from CloudWatch logs that the query is only being run <em>once</em>; I have a mutation running regularly on a timer that is successfully invoked and visible in CloudWatch. That is working as I'd expect but the query is not.</p>
  
  <p><strong>Update #3</strong>: I have debugged in to the AppSync/Apollo code and can see that my fetchPolicy is being changed to 'cache-first' in this code in <code>apollo-client/core/QueryManager.js</code> (comments mine):</p>
  
  <pre><code>QueryManager.prototype.fetchQuery = function (queryId, options, fetchType, fetchMoreForQueryId) {
      var _this = this;
      // Next line changes options.fetchPolicy to 'cache-first'
      var _a = options.variables, variables = _a === void 0 ? {} : _a, _b = options.metadata, metadata = _b === void 0 ? null : _b, _c = options.fetchPolicy, fetchPolicy = _c === void 0 ? 'cache-first' : _c;
      var cache = this.dataStore.getCache();
      var query = cache.transformDocument(options.query);
      var storeResult;
      var needToFetch = fetchPolicy === 'network-only' || fetchPolicy === 'no-cache';
      // needToFetch is false (because fetchPolicy is 'cache-first')
      if (fetchType !== FetchType.refetch &amp;&amp;
          fetchPolicy !== 'network-only' &amp;&amp;
          fetchPolicy !== 'no-cache') {
          // so we come through this branch
          var _d = this.dataStore.getCache().diff({
              query: query,
              variables: variables,
              returnPartialData: true,
              optimistic: false,
          }), complete = _d.complete, result = _d.result;
          // here complete is true, result is from the cache
          needToFetch = !complete || fetchPolicy === 'cache-and-network';
          // needToFetch is still false
          storeResult = result;
      }
      // skipping some stuff
      ...
      if (shouldFetch) { // shouldFetch is still false so this doesn't execute
          var networkResult = this.fetchRequest({
              requestId: requestId,
              queryId: queryId,
              document: query,
              options: options,
              fetchMoreForQueryId: fetchMoreForQueryId,
      }
      // resolve with data from cache
      return Promise.resolve({ data: storeResult });
  </code></pre>
  
  <p>If I use my debugger to change the value of <code>shouldFetch</code> to true then at least I see a network request go out and my lambda executes. I guess I need to unpack what that line that is changing my fetchPolicy is doing.</p>