solicitudes paralelas a node.js, connect-mongo, sesión sobrescrita

En un proyecto actual (tipo de sistema de tienda), uso node.js con expressJS y connect-mongo como tienda de sesión. En el lado del cliente, utilizo una sola solicitud en el inicio para crear una nueva sesión y luego enviar varias solicitudes paralelas al servidor node.js. Debido a que estas solicitudes paralelas cambian la sesión, esos cambios parecen sobrescribirse entre sí, aunque, por supuesto, cambian diferentes objetos de la sesión.

Ejemplo (las 3 solicitudes comienzan al mismo tiempo):

  • La solicitud A req.session.productHist['abc'] algunos productos en la matriz req.session.productHist['abc']
  • La solicitud B empuja los productos a req.session.productHist['def']
  • La solicitud C lleva algún tiempo, pero no cambia la sesión

Debido a que la solicitud C finaliza después de la solicitud A y B, pero comienza antes de que finalice, parece que sobrescribe session.productHist con el valor que tenía cuando se inició la solicitud C (nula).

¿Cómo puedo arreglar esto?

Actualizar:

Algún código de ejemplo con salida de consola:

 var url = require('url'), express = require('express'), MongoStore = require('connect-mongo'); var aDay = 24*60*60*1000; var app = express.createServer(); app.configure(function(){ app.use(express.cookieParser()); app.use(express.session({ secret: "secret", store: new MongoStore({ db: 'lmsCache' }), maxAge: aDay }) ); app.use(express.methodOverride()); app.use(express.bodyParser()); app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); app.use(app.router); app.use(express.logger()); }); function sendStringified(req, res, data) { data = JSON.stringify(data); if (req.url_query.callback) { data = req.url_query.callback + "(" + data + ");"; } res.send(data); } function parseParams(req,res,next) { req.url_query = url.parse(req.url,true).query; next(); } function doExpensiveStuff(req,res,next) { console.log("######################### init start"); [...] } app.get('/init', parseParams, doExpensiveStuff, function(req,res) { console.log("init: session.productHist: " + JSON.stringify(req.session.productHist)); console.log("######################### init end"); sendStringified(req,res,null); }); app.get('/products', parseParams, function(req,res) { console.log("######################### products "+req.url_query.category+" start"); if(!req.session.productHist[req.url_query.category]) req.session.productHist[req.url_query.category] = []; for(var i=0;i<2;i++) { req.session.productHist[req.url_query.category].push({ "id": new Date().toGMTString() }); } console.log("products: session.productHist: " + JSON.stringify(req.session.productHist)); console.log("######################### products "+req.url_query.category+" end"); sendStringified(req,res,[]); }); app.get('/newSession', parseParams, function(req,res) { console.log("######################### newSession"); req.session.productHist = {}; sendStringified(req,res,true); }); app.listen(8080); time = new Date().toGMTString(); console.log('Server starting at: ' + time); 

Registro de la consola:

Servidor a partir de: jue, 15 dic 2011 15:50:37 GMT

################### nueva sesión
################### init start
################### products -1 start

productos: session.productHist: {“-1”: [{“id”: “Thu, 15 Dec 2011 15:50:40 GMT”}, {“id”: “Thu, 15 Dec 2011 15:50:40 GMT “}]}

################### products -1 end

init: session.productHist: {}

################### init end

[…]

################### products -1 start

productos: session.productHist: {“-1”: [{“id”: “Thu, 15 Dec 2011 15:50:53 GMT”}, {“id”: “Thu, 15 Dec 2011 15:50:53 GMT “}]}

################### products -1 end

Creo que he encontrado la respuesta a este problema difícil.

De la documentación de Express.js :

Properties on req.session are automatically saved on a response

Version corta

Cuando configura una variable de sesión ( req.session.my_var = value ), en realidad no se guarda (en ese momento exacto), sino más tarde (cuando envía la respuesta, en su caso, es cuando se res.send ). Eso causó tu problema.

Versión larga

Entonces, ¿qué significa eso exactamente?

  1. Realiza una solicitud, luego obtiene la variable de sesión (que se encuentra en el estado A) y luego hace algo con ella (eso requiere algún tiempo)
  2. Realiza otra solicitud y obtiene la variable de sesión (que aún se encuentra en el estado A porque la respuesta aún no se ha enviado) y le cambia algunas cosas.
  3. Ahora se ha realizado el procesamiento de la sesión, etc., así que envía la respuesta desde 1), modificando así la variable de sesión y llevándola al estado B
  4. Aquí viene la parte ‘divertida’, después de que enviaste la respuesta de 2). Ahora no está modificando realmente la sesión actual (que se ha actualizado al estado B), porque la respuesta se retrasó, por lo que lo que realmente está cambiando es la sesión del estado A, lo que lleva al estado C => lo que significa que todos Las modificaciones del estado B se perdieron!