即使禁用了离线功能,AWS AppSync查询也会返回缓存的响应

时间:2018-07-12 13:28:15

标签: amazon-web-services apollo apollo-client aws-appsync

我有一个使用AWS AppSync的相当简单的节点应用程序。我能够成功运行查询和变异,但是最近发现,如果我运行两次查询,我将得到相同的响应-即使我知道后端数据已更改。在这种特殊情况下,查询由lambda支持,在深入研究中,我发现查询似乎并没有在网络上发送出去,因为lambda不会在每次查询运行时触发-只是第一次。如果我使用控制台模拟查询,则一切运行正常。如果我重新启动应用程序,则在第一次运行查询时它可以正常运行,但是连续的查询再次每次都返回相同的值。

这是我的代码的一部分:

  client.query({
    query: gql`
    query GetAbc($cId: String!) {
      getAbc(cId: $cId) {
        id
        name
        cs
      }
    }`,
    options: {
      fetchPolicy: 'no-cache'
    },
    variables: {
      cid: event.cid
    }
  })
    .then((data) => {
      // same data every time
    })

修改:尝试使用其他network-only这样的抓取策略没有明显区别。

这是我设置客户端的方式,虽然不是超级干净,但似乎可以正常工作:

const makeAWSAppSyncClient = (credentials) => {
  return Promise.resolve(
    new AWSAppSyncClient({
      url: 'lalala',
      region: 'us-west-2',
      auth: {
        type: 'AWS_IAM',
        credentials: () => {
          return credentials
        }
      },
      disableOffline: true
    })
  )
}

getRemoteCredentials()
  .then((credentials) => {
    return makeAWSAppSyncClient(credentials)
  })
  .then((client) => {
    return client.hydrated()
  })
  .then((client) => {
    // client is good to use
  })

getRemoteCredentials是一种将IoT身份验证转换为可与其他AWS开发工具包一起使用的常规IAM凭证的方法。这是可行的(因为如果没有的话,我将无法做到。)

我的问题似乎与此GraphQL Query Runs Sucessfully One Time and Fails To Run Again using Apollo and AWS AppSync类似;我在节点环境中运行(而不是做出反应),但这实际上是相同的问题。


我认为这无关紧要,但出于完整性考虑,我已经尝试过使用和不使用文档中的设置代码。这似乎没有什么区别(烦人的日志记录除外,请参见下文),但在这里是

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')

这取自:https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-javascript.html

使用此代码,并且在客户端设置中没有offlineDisabled: true的情况下,我看到此行在控制台上不断涌出:

  

redux-persist asyncLocalStorage需要一个全局localStorage对象。   请使用其他存储后端,或者这是通用的Redux   您可能应该有条件地像这样保留应用程序:   https://gist.github.com/rt2zz/ac9eb396793f95ff3c3b

但是,此问题没有明显的区别。


更新:我对package.json的依赖关系,我在测试过程中已对其进行了升级,因此yarn.lock包含的更新版本比此处列出的要多。不过:https://gist.github.com/macbutch/a319a2a7059adc3f68b9f9627598a8ca

更新#2 :我还从CloudWatch日志中确认,查询仅在一次上运行;我有一个在计时器上定期运行的变异,该变异已成功调用并在CloudWatch中可见。符合我的预期,但查询没有。

更新#3 :我已调试到AppSync / Apollo代码,并且可以在apollo-client/core/QueryManager.js的此代码中看到将我的fetchPolicy更改为“缓存优先”(注释我的):

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 &&
        fetchPolicy !== 'network-only' &&
        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 });

如果我使用调试器将shouldFetch的值更改为true,那么至少我看到一个网络请求传出并且lambda执行。我想我需要解压正在改变fetchPolicy的那一行在做什么。

3 个答案:

答案 0 :(得分:3)

好的,我发现了问题。这是我的问题的代码缩写:

 client.query({
    query: gql`...`,
    options: {
      fetchPolicy: 'no-cache'
    },
    variables: { ... }
  })

在这里看哪里出了问题要容易一些。这应该是这样:

 client.query({
    query: gql`...`,
    fetchPolicy: 'network-only'
    variables: { ... }
  })

原件中的两个问题:

  1. fetchPolicy: 'no-cache'在这里似乎不起作用(我得到的答复是空的)
  2. 不需要将fetchPolicy放在options对象中

graphql客户端指定选项的方式有所不同,我们正在两者之间进行切换。

答案 1 :(得分:2)

在AWS Lambda函数中运行时,将查询foreach设置为$source1 = "Y:\New Documents\test.txt" foreach ($line in Get-Content $source1) { $find = $line (Get-Content $source1).replace($find,"") | Set-Content $source1 }

我建议对fetch-policy'network-only'WebSocket使用替代,因为这些对象实际上并不适用于Lambda函数。我通常在Lambda中用于NodeJS应用程序的设置如下所示。

window

答案 2 :(得分:0)

对于每个查询或/和初始化客户端,有两个选项可启用/禁用AppSyncClient / ApolloClient的缓存。

客户端配置:

client = new AWSAppSyncClient(
  {
    url: 'https://myurl/graphql',
    region: 'my-aws-region',
    auth: {
      type: AUTH_TYPE.AWS_MY_AUTH_TYPE,
      credentials: await getMyAWSCredentialsOrToken()
    },
    disableOffline: true
  },
  {
    cache: new InMemoryCache(),
    defaultOptions: {
      watchQuery: {
        fetchPolicy: 'no-cache', // <-- HERE: check the apollo fetch policy options
        errorPolicy: 'ignore'
      },
      query: {
        fetchPolicy: 'no-cache',
        errorPolicy: 'all'
      }
    }
  }
);

替代:查询选项:

export default graphql(gql`query { ... }`, {
    options: { fetchPolicy: 'cache-and-network' },
})(MyComponent);

有效的fetchPolicy值为:

  • 缓存优先:这是默认值,我们始终尝试首先从您的缓存中读取数据。如果满足查询所需的所有数据都在高速缓存中,则将返回该数据。仅当没有缓存结果时,Apollo才会从网络获取。此提取策略旨在最大程度地减少渲染组件时发送的网络请求。
  • 缓存和网络:此提取策略将使Apollo首先尝试从缓存中读取数据。如果满足查询所需的所有数据都在高速缓存中,则将返回该数据。但是,无论是否在缓存中保存了全部数据,与cache-first不同,此fetchPolicy始终会通过网络接口执行查询,readQuery()仅在查询数据不在缓存中时才执行查询。此提取策略可优化用户的响应速度,同时还可以使缓存的数据与服务器数据保持一致,但需要额外的网络请求。
  • 仅限网络:此提取策略将永远不会从缓存中返回初始数据。相反,它将始终使用您的网络接口向服务器发出请求。这种获取策略可优化与服务器的数据一致性,但是会以可用时对用户的即时响应为代价。
  • 仅缓存:此提取策略将永远不会使用您的网络接口执行查询。相反,它将始终尝试从缓存中读取。如果用于查询的数据在缓存中不存在,则将引发错误。此获取策略允许您仅与本地客户端缓存中的数据进行交互,而无需发出任何网络请求,从而使组件保持快速运行,但是这意味着您的本地数据可能与服务器上的数据不一致。如果只对与ApolloClient缓存中的数据进行交互感兴趣,还请确保查看ApolloClient实例上可用的readFragment()和{{1}}方法。
  • 无缓存:此提取策略将永远不会从缓存中返回您的初始数据。相反,它将始终使用您的网络接口向服务器发出请求。与仅限网络的策略不同,查询完成后,它也不会将任何数据写入缓存。

复制自:https://www.apollographql.com/docs/react/api/react-hoc/#graphql-options-for-queries