即使离线被禁用,AWS AppSync 查询也会返回缓存的响应 [英] AWS AppSync query returns cached response even when offline is disabled

查看:27
本文介绍了即使离线被禁用,AWS AppSync 查询也会返回缓存的响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这是我的部分代码:

 client.query({查询:gql`查询 GetAbc($cId: String!) {getAbc(cId: $cId) {ID姓名CS}}`,选项: {fetchPolicy: '无缓存'},变量:{cid:事件.cid}}).then((数据) => {//每次都相同的数据})

编辑:尝试其他获取策略(例如 network-only)没有明显区别.

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

const makeAWSAppSyncClient = (credentials) =>{返回 Promise.resolve(新的 AWSAppSyncClient({网址:'拉拉拉',地区:'us-west-2',授权:{类型:'AWS_IAM',凭据:() =>{返回凭据}},禁用离线:真}))}getRemoteCredentials().then((凭据) => {返回 makeAWSAppSyncClient(凭证)}).then((客户端) => {返回 client.hydred()}).then((客户端) => {//客户端很好用})

getRemoteCredentials 是一种将 IoT 身份验证转换为可与其他 AWS 开发工具包一起使用的普通 IAM 凭证的方法.这是有效的(因为如果不这样做,我就不会走得那么远).

我的问题似乎与这个问题非常相似 GraphQL 查询成功运行一次,但使用 Apollo 和 AWS AppSync 再次运行失败;我在节点环境中运行(而不是反应),但本质上是相同的问题.

<小时>

我不认为这是相关的,但为了完整起见,我应该提到我已经尝试过使用和不使用文档中的设置代码.这似乎没有什么区别(除了烦人的日志记录,见下文)但这里是:

global.WebSocket = require('ws')global.window = global.window ||{设置超时:设置超时,清除超时:清除超时,WebSocket: global.WebSocket,ArrayBuffer: global.ArrayBuffer,addEventListener: 函数 () { },导航器:{在线:真}}global.localStorage = {店铺: {},getItem:函数(键){返回 this.store[key]},setItem:函数(键,值){this.store[key] = 值},removeItem:功能(键){删除 this.store[key]}};require('es6-promise').polyfill()要求('同构获取')

这取自: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/a319a2a7059adc3f68b9f962>759a

更新 #2:我还从 CloudWatch 日志中确认查询仅运行一次;我有一个在计时器上定期运行的突变,该计时器已成功调用并在 CloudWatch 中可见.这正如我所期望的那样工作,但查询不是.

更新 #3:我已经调试到 AppSync/Apollo 代码中,可以看到我的 fetchPolicy 在 apollo-client/中的这段代码中被更改为缓存优先"core/QueryManager.js(我的评论):

QueryManager.prototype.fetchQuery = function (queryId, options, fetchType, fetchMoreForQueryId) {var _this = this;//下一行将 options.fetchPolicy 更改为 '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 ?'缓存优先':_c;var cache = this.dataStore.getCache();var query = cache.transformDocument(options.query);var storeResult;var needToFetch = fetchPolicy === '仅限网络' ||fetchPolicy === '无缓存';//needToFetch 为假(因为 fetchPolicy 是 'cache-first')if (fetchType !== FetchType.refetch &&fetchPolicy !== '仅限网络' &&fetchPolicy !== '无缓存') {//所以我们通过这个分支var _d = this.dataStore.getCache().diff({查询:查询,变量:变量,返回部分数据:真,乐观:假,}), 完成 = _d.complete, 结果 = _d.result;//这里完成为真,结果来自缓存needToFetch = !complete ||fetchPolicy === '缓存和网络';//needToFetch 仍然是假的storeResult = 结果;}//跳过一些东西...if (shouldFetch) {//shouldFetch 仍然是假的所以这不会执行var networkResult = this.fetchRequest({请求 ID:请求 ID,查询 ID:查询 ID,文件:查询,选项:选项,fetchMoreForQueryId: fetchMoreForQueryId,}//使用缓存中的数据解析返回 Promise.resolve({ data: storeResult });

如果我使用调试器将 shouldFetch 的值更改为 true,那么至少我会看到一个网络请求发出并且我的 lambda 执行.我想我需要解开改变我的 fetchPolicy 的那行代码.

解决方案

好的,我找到了问题.这是我的问题中代码的缩写版本:

 client.query({查询:gql`...`,选项: {fetchPolicy: '无缓存'},变量:{ ... }})

更容易看出这里出了什么问题.应该是这样的:

 client.query({查询:gql`...`,fetchPolicy: '仅限网络'变量:{ ... }})

我原来的两个问题:

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

graphql 客户端以不同的方式指定选项,我们在两者之间切换.

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.

Here are some part of my 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) => {
      // same data every time
    })

Edit: trying other fetch policies like network-only makes no visible difference.

Here is how I set up the client, not super clean but it seems to work:

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

My issue seems very similar to this one GraphQL Query Runs Sucessfully One Time and Fails To Run Again using Apollo and AWS AppSync; I'm running in a node environment (rather than react) but it is essentially the same issue.


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:

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

This is taken from: https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-javascript.html

With this code and without offlineDisabled: true in the client setup I see this line spewed continuously on the console:

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: https://gist.github.com/rt2zz/ac9eb396793f95ff3c3b

This makes no apparent difference to this issue however.


Update: my dependencies from package.json, I have upgraded these during testing so my yarn.lock contains more recent revisions than listed here. Nevertheless: https://gist.github.com/macbutch/a319a2a7059adc3f68b9f9627598a8ca

Update #2: I have also confirmed from CloudWatch logs that the query is only being run once; 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.

Update #3: 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 apollo-client/core/QueryManager.js (comments mine):

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 });

If I use my debugger to change the value of shouldFetch 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.

解决方案

OK I found the issue. Here's an abbreviated version of the code from my question:

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

It's a little bit easier to see what is wrong here. This is what it should be:

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

Two issues in my original:

  1. fetchPolicy: 'no-cache' does not seem to work here (I get an empty response)
  2. putting the fetchPolicy in an options object is unnecessary

The graphql client specifies options differently and we were switching between the two.

这篇关于即使离线被禁用,AWS AppSync 查询也会返回缓存的响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆