В настоящее время я играю с транзакциями в последнем доступном образе докера MongoDB 4.1.4 (используя Node 8.12.0 и Mongoose 5.3.8 в качестве клиента). Я сделал простой набор реплик с 3 экземплярами Монго, все работает отлично и все, пока я не сделаю много 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();
Пока все работает, пока я не раскомментирую переход в коллекцию Google 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' } });