javascript - 错误:10 中止:对这些文档的争用过多。请再试一次
问题描述
这个错误是什么意思?
特别是,它们是什么意思:请重试
这是否意味着交易失败我必须手动重新运行交易?根据我从文档中了解到的情况,
事务读取在事务之外修改的文档。在这种情况下,事务会自动再次运行。事务被重试有限次。
如果有,在哪些文件上?该错误不指示它正在谈论的文档。我刚得到这个堆栈:
{ 错误:10 中止:对这些文档的争用过多。请再试一次。在 Object.exports.createStatusErrornode_modules\grpc\src\common.js:87:15) 在 ClientReadableStream._emitStatusIfDone \node_modules\grpc\src\client.js:235:26) 在 ClientReadableStream._receiveStatus \node_modules\grpc\src\client .js:213:8) 在 Object.onReceiveStatus \node_modules\grpc\src\client_interceptors.js:1256:15) 在 InterceptingListener._callNext node_modules\grpc\src\client_interceptors.js:564:42) 在 InterceptingListener.onReceiveStatus\node_modules \grpc\src\client_interceptors.js:614:8) 在 C:\Users\Tolotra Samuel\PhpstormProjects\CryptOcean\node_modules\grpc\src\client_interceptors.js:1019:24 代码:10,元数据:元数据 { _internal_repr: { } }, details: '对这些文件的争论太多了。请再试一次。
要重新创建此错误,只需按照文档中的说明在 db.runTransaction 方法上运行 for 循环
解决方案
我们在使用 Firebase Firestore 数据库时遇到了同样的问题。即使是少于 30 件物品的小型柜台也无法计算遇到此问题的地方。
我们的解决方案不是分配计数器,而是增加事务的尝试次数并为这些重试添加延迟时间。
第一步是保存事务操作,因为 const witch 可以传递给另一个函数。
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 的中止错误,我们只需再次运行事务以进行特定数量的重试。
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
我们的事务调用将运行比默认调用更长的时间,并且它会及时延迟。
await runTransaction(taskCountTransaction)
我喜欢这个解决方案的地方在于它并不意味着更多或更复杂的代码,并且大多数已经编写的代码可以保持原样。只有当计数器达到必须计算更多项目的程度时,它才会使用更多时间和资源。否则,时间和资源与您将拥有默认事务相同。
为了扩大大量项目,我们可以增加重试次数或等待时间。两者都在影响 Firebase 的成本。对于等待部分,我们还需要增加函数的超时时间。
免责声明:我没有用数千个或更多项目对这段代码进行压力测试。在我们的具体案例中,问题从 20 多个项目开始,我们需要多达 50 个项目来完成一项任务。我用 200 个项目对其进行了测试,并且问题没有再次出现。
推荐阅读
- python - 随机数据帧 - 总和和平均值
- android - 在 API 级别 28 中找不到 Canvas 变量
- testing - 赛普拉斯不匹配路线
- javascript - 检查 JS 或 TS 中的标识符中是否存在字符串值
- prometheus - 获取自上次增加 Prometheus 计数器以来经过的时间
- heroku - 使用 Heroku Pipelines 同时部署前端和后端
- java - 如何以编程方式设置自定义布局属性
- c++ - 在固定大小的数组上展开 C++ 中的循环是否有益?
- javascript - 如何以编程方式在 Lighthouse 中设置自定义配置?
- java - 减少一个 Map,其中键是某些条目中的值