Prevención de condiciones de carrera relacionadas con la base de datos en Node.js

Visión general

Estoy tratando de entender cómo garantizar la seguridad sincrónica al usar una instancia de un modelo al usar Node.js. Aquí, uso el ODM Mongoose en ejemplos de código, pero la pregunta se aplica a cualquier caso en el que se use una base de datos con el enfoque de E / S controlado por eventos asíncronos que emplea Node.js.

Considere el siguiente código (que utiliza Mongoose para consultas de MongoDB):

Fragmento A

MyModel.findOne( { _id :  }, 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' ); } }); }); 

En una parte separada de la aplicación, el documento descrito por MyModel podría actualizarse. Considere el siguiente código:

Fragmento B

 MyModel.update( { _id :  }, { $set : { field1 : someValue }, callback ); 

En el Fragmento A, se emite una consulta MongoDB con una callback registrada que se activará una vez que el documento esté listo. Una instancia del documento descrito por MyModel se conserva en la memoria (en el objeto “doc”). La siguiente secuencia podría ocurrir:

  1. Fragmento A ejecuta
  2. Se inicia una consulta para MyModel, registrando una callback (callback A) para su uso posterior
  3. <>
  4. MyModel se recupera de la base de datos, ejecutando la callback registrada (callback A)
  5. Se inicia una consulta para MyOtherModel, registrando una callback para su uso posterior (callback B)
  6. <>
  7. Snippet B ejecuta
  8. El documento (id # 1) se actualiza
  9. <>
  10. MyOtherModel se recupera de la base de datos, ejecutando la callback registrada (callback B)
  11. La versión obsoleta del documento (id # 1) se usa incorrectamente en una comparación.

Preguntas

  1. ¿Hay alguna garantía de que este tipo de condición de carrera no ocurra en Node.js / MongoDB?
  2. ¿Qué puedo hacer para evitar que este escenario ocurra de manera determinista?

Si bien Node ejecuta el código de una manera de un solo hilo, me parece que cualquier asignación del bucle de evento para ejecutarse abre la puerta a datos potencialmente obsoletos. Por favor corrígeme si esta observancia es incorrecta.

No, no hay garantías de que este tipo de condición de carrera no ocurra en node.js / MongoDB. Sin embargo, no tiene nada que ver con node.js, y esto es posible con cualquier base de datos que admita el acceso simultáneo, no solo MongoDB.

Sin embargo, el problema es más difícil de resolver con MongoDB porque no admite transacciones como lo haría una base de datos SQL típica. Por lo tanto, debe resolverlo en su capa de aplicación utilizando una estrategia como la que se describe en el libro de cocina de MongoDB aquí .