Обзор
Я пытаюсь понять, как обеспечить асинхронную безопасность при использовании экземпляра модели при использовании Node.js. Здесь я использую Mongoose ODM в образцах кода, но этот вопрос применим ко всем случаям, когда база данных используется с асинхронным подходом ввода-вывода, основанным на событиях, который использует Node.js.
Рассмотрим следующий код (который использует запросы Mongoose для MongoDB):
Фрагмент A
MyModel.findOne( { _id : <id #1> }, function( err, doc ) {
MyOtherModel.findOne( { _id : someOtherId }, ( function(err, otherDoc ) {
if (doc.field1 === otherDoc.otherField) {
doc.field2 = 0; // assign some new value to a field on the model
}
doc.save( function() { console.log( 'success' ); }
});
});
В отдельной части приложения документ, описанный MyModel, может быть обновлен. Рассмотрим следующий код:
Фрагмент B
MyModel.update( { _id : <id #1> }, { $set : { field1 : someValue }, callback );
В Snippet A запрос MongoDB выдается с зарегистрированным обратным вызовом, который должен быть запущен, как только документ будет готов. Экземпляр документа, описанный MyModel, сохраняется в памяти (в объекте doc). Возможна следующая последовательность:
- Фрагмент A выполняется
- Для MyModel инициируется запрос, регистрирующий обратный вызов (обратный вызов A) для последующего использования
- < < Цикл событий Node запускается →
- MyModel извлекается из базы данных, выполняя зарегистрированный обратный вызов (обратный вызов A)
- Для MyOtherModel инициируется запрос, регистрирующий обратный вызов для последующего использования (обратный вызов B)
- < < Цикл событий Node запускается →
- Фрагмент B выполняется
- Обновлен документ (id # 1)
- < < Цикл событий Node запускается →
- MyOtherModel извлекается из базы данных, выполняя зарегистрированный обратный вызов (обратный вызов B)
- В сравнении неверно используется устаревшая версия документа (id # 1).
Вопросы
- Есть ли какие-либо гарантии, что такого рода состояние гонки не произойдет в Node.js/MongoDB?
- Что я могу сделать, чтобы детерминистически предотвратить этот сценарий?
В то время как Node запускает код однопоточным образом, мне кажется, что любое допущение цикла цикла запускает дверь для потенциально устаревших данных. Пожалуйста, исправьте меня, если это соблюдение неверно.