параллельные запросы к node.js, connect-mongo, сессия перезаписаны - PullRequest
5 голосов
/ 14 декабря 2011

В текущем проекте (тип системы магазинов) я использую node.js с expressJS и connect-mongo в качестве хранилища сеансов.На стороне клиента я использую один запрос при запуске, чтобы создать новый сеанс и впоследствии отправить несколько параллельных запросов на сервер node.js.Поскольку эти параллельные запросы изменяют сеанс, эти изменения, по-видимому, перезаписывают друг друга, хотя, конечно, они изменяют различные объекты сеанса.

Пример (все 3 запроса начинаются одновременно):

  • Запрос A помещает некоторые продукты в массив req.session.productHist['abc']
  • Запрос B переводит продукты в req.session.productHist['def']
  • Запрос C занимает некоторое время, но не меняет сеанс

Поскольку запрос C завершается после запроса A и B, но запускается до того, как они закончатся, он перезаписывает session.productHist значением, которое он удерживал при запуске запроса C (ноль).

Как это исправить?

Обновление:

Пример кода с консольным выводом:

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);  

Журнал консоли:

Сервер, начиная с: четверг, 15 декабря 2011 г., 15:50:37 GMT

################### newSession################### init start################### products -1 start

products: session.productHist: {"-1": [{"id": "Четверг, 15 декабря 2011 г.15:50:40 GMT "}, {" id ":" Четверг, 15 декабря 2011 г. 15:50:40 GMT "}]}

################### продукты -1 конец

init: session.productHist: {}

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

[...]

################### продукты -1 начало

products: session.productHist: {"-1": [{"id": "Чт, 15 декабря 2011 15:50:53 GMT"}, {"id": "Чт, 15 декабря 2011 15:50: 53 GMT "}]}

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

1 Ответ

3 голосов
/ 15 декабря 2011

Я думаю, что нашел ответ на эту хитрую проблему.

Из документации Express.js :

Properties on req.session are automatically saved on a response

Короткая версия

Когда вы устанавливаете переменную сеанса (req.session.my_var = value), она фактически не сохраняется тогда (в тот самый момент), но позже (когда вы отправляете ответ, в вашем случае этокогда вы делаете res.send).Это вызвало вашу проблему.

Длинная версия

Так, что это значит точно?

  1. Вы делаете запрос, затем получаете сеанспеременная (которая находится в состоянии A) и после этого сделать что-то с ней (что требует некоторого времени)
  2. Вы делаете другой запрос и получаете переменную сеанса (которая все еще находится в состоянии A, потому что ответ не былеще не отправлено) и измените некоторые вещи на него
  3. Теперь обработка сеанса и т. д. выполнена, поэтому вы отправляете ответ из 1), изменяя таким образом переменную сеанса и переводя ее в состояние B
  4. Здесьприходит «веселая» часть, после того как вы отправили ответ от 2).Теперь вы на самом деле не изменяете текущий сеанс (который был обновлен до состояния B), потому что ответ был отложен, поэтому вы фактически меняете сеанс из состояния A, переводя его в состояние C =>, что означает всемодификации из состояния B были потеряны!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...