我目前正在MongoDB 4.1.4的最新可用docker映像中处理事务(使用Node 8.12.0和Mongoose 5.3.8作为客户端)。我用3个mongo示例做了一个简单的副本集,一切都很好,直到我在短时间内出现了很多WriteConflict
错误。
我的代码如下所示:
// name, value are strings
// date is current time
const session = await createAnalyticsTransaction(); // returns 'session'
// _id is pregenerated
var stat = await Logger.findById(_id).session(session);
if (stat) {
// do nothing if it already exists
return true;
}
await Logger.update({
_id
}, {
$setOnInsert: {
_id,
name,
created: date.toDate(),
modified: date.toDate()
}
}, {
session,
upsert: true
});
/*
var period = 'month';
var time = '2018-11';
await Analytics.update({
_id
}, {
$setOnInsert: {
_id,
name,
period,
time,
created: date.toDate()
},
$inc: inc
}, {
upsert: true,
session: session
});
*/
await session.commitTransaction();
await session.endSession();
到目前为止,一切都正常,直到我取消注解一个upsert到Analytics集合中的$inc
和$setOnInsert
,并同时运行大约1000个操作。我的想法是,如果Analytics集合还没有创建,就应该创建它。然后我开始得到很多MongoError: WriteConflict
,错误的属性errorLabels
具有TransientTransactionError
。
我猜是因为$inc
或upsert: true
?有人经历过吗?在这种情况下最好的解决方案是什么?
{ MongoError: WriteConflict
at /Users/akuzmenok/Zend/MeteorLingua/lingua-analytics/node_modules/mongodb-core/lib/connection/pool.js:581:63
at authenticateStragglers (/Users/akuzmenok/Zend/MeteorLingua/lingua-analytics/node_modules/mongodb-core/lib/connection/pool.js:504:16)
at Connection.messageHandler (/Users/akuzmenok/Zend/MeteorLingua/lingua-analytics/node_modules/mongodb-core/lib/connection/pool.js:540:5)
at emitMessageHandler (/Users/akuzmenok/Zend/MeteorLingua/lingua-analytics/node_modules/mongodb-core/lib/connection/connection.js:310:10)
at Socket.<anonymous> (/Users/akuzmenok/Zend/MeteorLingua/lingua-analytics/node_modules/mongodb-core/lib/connection/connection.js:453:17)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at Socket.Readable.push (_stream_readable.js:208:10)
at TCP.onread (net.js:597:20)
=> awaited here:
at Function.Promise.await (/Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:56:12)
at Promise.asyncApply (imports/lib/analytics.js:97:9)
at /Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:43:40
=> awaited here:
at Function.Promise.await (/Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:56:12)
at Promise.asyncApply (imports/lib/analytics.js:139:5)
at /Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:43:40
=> awaited here:
at Function.Promise.await (/Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:56:12)
at Promise.asyncApply (imports/lib/analytics.js:158:5)
at /Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:43:40
=> awaited here:
at Function.Promise.await (/Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:56:12)
at Promise.asyncApply (imports/lib/analytics.js:49:23)
at /Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:43:40
=> awaited here:
at Function.Promise.await (/Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:56:12)
at Promise.asyncApply (imports/lib/analytics.js:14:23)
at /Users/akuzmenok/.meteor/packages/promise/.0.11.1.1ugu6ow.mjjhg++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:43:40
errorLabels: [ 'TransientTransactionError' ],
operationTime: Timestamp { _bsontype: 'Timestamp', low_: 12, high_: 1541424838 },
ok: 0,
errmsg: 'WriteConflict',
code: 112,
codeName: 'WriteConflict',
'$clusterTime':
{ clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 12, high_: 1541424838 },
signature: { hash: [Object], keyId: 0 } },
name: 'MongoError',
[Symbol(mongoErrorContextSymbol)]: {} }
另一个注意事项,我将启动一个事务,如下所示:
const session = await MongoAnalytics.startSession({ causalConsistency: true });
session.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' } });
2条答案
按热度按时间iezvtpos1#
从数据库读取数据,然后更新数据。如下所示:
当执行两个异步调用时:
它返回一个错误,因为数据的状态改变了。这就是事务应该如何工作的。
为了避免访问冲突,您可以实现一个自定义队列系统,或者捕获错误并使用setTimeout重新运行事务,该setTimeout具有最大尝试次数。
排队系统:
重新运行系统
cwxwcias2#
在成功和失败中做到这一点