错误:10 ABORTED:对这些文档的争用过多.请再试一次 [英] Error: 10 ABORTED: Too much contention on these documents. Please try again

查看:16
本文介绍了错误:10 ABORTED:对这些文档的争用过多.请再试一次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个错误是什么意思?

特别是,它们是什么意思:请重试

Especially, what do they mean by : Please try again

是否意味着交易失败我必须手动重新运行交易?根据我从文档中的理解,

Does it mean that the transaction failed I have to re-run the transaction manually? From what I understood from the documentation,

事务读取了在外部修改的文档交易.在这种情况下,事务会自动再次运行.事务重试有限次数.

The transaction read a document that was modified outside of the transaction. In this case, the transaction automatically runs again. The transaction is retried a finite number of times.

如果是,在哪些文件上?该错误不表明它在谈论哪个文档.我只是得到这个堆栈:

If so, on which documents? The error do not indicate which document it is talking about. I just get this stack:

{ 错误:10 ABORTED:对这些文档的争用过多.请再试一次.在 Object.exports.createStatusErrornode_modulesgrpcsrccommon.js:87:15)在 ClientReadableStream._emitStatusIfDone ode_modulesgrpcsrcclient.js:235:26)在 ClientReadableStream._receiveStatus ode_modulesgrpcsrcclient.js:213:8)在 Object.onReceiveStatus ode_modulesgrpcsrcclient_interceptors.js:1256:15)在 InterceptingListener._callNext node_modulesgrpcsrcclient_interceptors.js:564:42)在 InterceptingListener.onReceiveStatus ode_modulesgrpcsrcclient_interceptors.js:614:8)在 C:UsersTolotra SamuelPhpstormProjectsCryptOcean ode_modulesgrpcsrcclient_interceptors.js:1019:24代码:10,元数据:元数据{_internal_repr:{}​​},细节:'太对这些文件的争论很多.请再试一次.'}

{ Error: 10 ABORTED: Too much contention on these documents. Please try again. at Object.exports.createStatusErrornode_modulesgrpcsrccommon.js:87:15) at ClientReadableStream._emitStatusIfDone ode_modulesgrpcsrcclient.js:235:26) at ClientReadableStream._receiveStatus ode_modulesgrpcsrcclient.js:213:8) at Object.onReceiveStatus ode_modulesgrpcsrcclient_interceptors.js:1256:15) at InterceptingListener._callNext node_modulesgrpcsrcclient_interceptors.js:564:42) at InterceptingListener.onReceiveStatus ode_modulesgrpcsrcclient_interceptors.js:614:8) at C:UsersTolotra SamuelPhpstormProjectsCryptOcean ode_modulesgrpcsrcclient_interceptors.js:1019:24 code: 10, metadata: Metadata { _internal_repr: {} }, details: 'Too much contention on these documents. Please try again.' }

要重现此错误,只需按照 文档

To recreate this error, just run a for loop on the db.runTransaction method as indicated on the documentation

推荐答案

我们遇到了与 Firebase Firestore 数据库相同的问题.即使是少于 30 件商品的小柜台,也能找出遇到此问题的地方.

We run into the same problem with the Firebase Firestore database. Even small counters with less then 30 items to cound where running into this issue.

我们的解决方案不是分发计数器,而是增加事务的尝试次数,并为这些重试增加延迟时间.

Our solution was not to distribute the counter but to increase the number of tries for the transaction and to add a deffer time for those retries.

第一步是保存事务操作,因为 const 可以传递给另一个函数.

The first step was to save the transaction action as const witch could be passed to another function.

const taskCountTransaction = async transaction => {
  const taskDoc = await transaction.get(taskRef)

  if (taskDoc.exists) {
    let increment = 0
    if (change.after.exists && !change.before.exists) {
      increment = 1
    } else if (!change.after.exists && change.before.exists) {
      increment = -1
    }

    let newCount = (taskDoc.data()['itemsCount'] || 0) + increment
    return await transaction.update(taskRef, { itemsCount: newCount > 0 ? newCount : 0 })
  }

  return null
}

第二步是创建两个辅助函数.一个用于等待特定的时间,另一个用于运行事务并捕获错误.如果出现代码为 10 的中止错误,我们只需再次运行事务进行特定数量的重试.

The second step was to create two helper functions. One for waiting a specifix amount of time and the other one to run the transaction and catch errors. If the abort error with the code 10 occurs we just run the transaction again for a specific amount of retries.

const wait = ms => { return new Promise(resolve => setTimeout(resolve, ms))}


const runTransaction = async (taskCountTransaction, retry = 0) => {
  try {
    await fs.runTransaction(taskCountTransaction)
    return null
  } catch (e) {
    console.warn(e)
    if (e.code === 10) {
      console.log(`Transaction abort error! Runing it again after ${retry} retries.`)

      if (retry < 4) {
        await wait(1000)
        return runTransaction(taskCountTransaction, ++retry)
      }
    }
  }
}

现在我们拥有了所需的一切,我们只需使用 await 调用我们的辅助函数,我们的事务调用将比默认调用运行更长时间,并且会及时延迟.

Now that we have all we need we can just call our helper function with await and our transaction call will run longer then a default one and it will deffer in time.

await runTransaction(taskCountTransaction)

我喜欢这个解决方案的地方在于它并不意味着更多或复杂的代码,而且大部分已经编写的代码可以保持原样.仅当计数器达到必须计算更多项目的程度时,它才会使用更多时间和资源.否则时间和资源与您拥有默认事务的时间和资源相同.

What I like about this solution is that it doesn't mean more or complicated code and that most of the already written code can stay as it is. It also uses more time and resources only if the counter gets to the point that it has to count more items. Othervise the time and resources are the same as if you would have the default transactions.

为了扩展大量项目,我们可以增加重试次数或等待时间.两者也在影响 Firebase 的成本.对于等待部分,我们还需要增加函数的超时时间.

For scaling up for large amounts of items we can increase eather the amount of retries or the waiting time. Both are also affecting the costs for Firebase. For the waiting part we also need to increase the timeout for our function.

免责声明:我没有用数千个或更多的项目对此代码进行压力测试.在我们的特定案例中,问题始于 20 多个项目,我们需要多达 50 个项目来完成一项任务.我用 200 个项目对其进行了测试,问题没有再次出现.

DISCLAIMER: I have not stress tested this code with thousands or more of items. In our specific case the problems started with 20+ items and we need up to 50 items for a task. I tested it with 200 items and the problem did not apear again.

这篇关于错误:10 ABORTED:对这些文档的争用过多.请再试一次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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