2011-12-14 5 views
5

を上書きし、Iは接続-MongoのをセッションストアとしてexpressJSとのNode.jsを使用して。クライアント側では、起動時に1つのリクエストを使用して新しいセッションを作成し、その後に複数のパラレルリクエストをnode.jsサーバーに送信します。 これらの並列要求はセッションを変更するため、セッションの異なるオブジェクトを変更するものの、それらの変更は互いに上書きされているように見えます。平行要求、接続-モンゴを、セッションが現在のプロジェクト(店舗システムの一種)で

例(すべての3つの要求を同時に開始):

  • 要求A配列にいくつかの製品をプッシュreq.session.productHist['abc']
  • リクエストBがCは、いくつかの時間がかかるreq.session.productHist['def']
  • 要求に製品を押す、しかしセッションを変更しない

要求CはリクエストAとBの後に終了するが、終了する前に開始するため、を上書きしているように見えるは、要求Cが開始されたときに保持されていた値(null)で保持されます。

どうすればこの問題を解決できますか?

更新:

コンソール出力を持ついくつかのサンプルコード:

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

コンソールログ:

Serverはから始まる:木、2011年午後03時50分37秒GMT 12月15日

########### newSession
########### init start
###########製品-1開始

製品:session.productHist:{"-1":[{"id": "2011年12月15日15:50:40 GMT"}、{"id": "Thu、15 Dec 2011 15:50:40 GMT "}]}

###################製品-1端


INIT:session.productHist:{}

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


[...]

###################製品は

製品を開始-1:session.productHistを:{ "-1":[{ "id": "Thu、2011年12月15日15:50:53 GMT"}、{"id": "2011年12月15日15:50:15 GMT"}}}

######## ####### ########## products -1 end
+0

AとBの後にCを要求できません。 – alessioalex

+0

可能であれば、パラレルリクエストをどこかで送信できるようにしたいと考えています。私はCが終了した後にA&Bを送信することができますが、それはユーザーエクスペリエンスを遅くします – jb90

+0

リクエストCはどうにもなりません.. – alessioalex

答えて

3

私はこのトリッキーな問題の答えを見つけたと思います。

Express.jsドキュメントから

Properties on req.session are automatically saved on a response

ショートバージョン

あなたはセッション変数(req.session.my_var = value)、それは実際に(その瞬間に)その後、保存されていないを設定し、それ以降の(応答を送信するときは、あなたの場合はres.sendです)。それはあなたの問題を引き起こしました。

ロングバージョン

は、だからそれは正確に何を意味するのでしょうか?

  1. あなたは(あなたが別の要求を作成し、セッション変数を取得
  2. (つまり、ある程度の時間を要する)(状態Aである)セッション変数を取得し、その後、それに何かをした後、要求を作成します応答がまだ送信されていないために状態Aになっています)。
  3. セッションの処理などが行われ、1)からの応答を送信してセッション変数を変更し、状態B
  4. あなたが2)からの応答を送った後、ここでは「楽しい」部分が来ます。これで、現在のセッション(状態Bに更新されています)は実際には変更されていません。応答が遅れたため、実際に状態AからのセッションがC =>状態になります状態Bからの変更は失われました!
+0

これは問題だと思いますが、その解決策はありますか?私はnode.jsのメモリでセッション全体をミラーリングすることができたと思いますが、それはmongoストレージをある点まで不要にして(そして大きなオーバーヘッドを作成するように)素晴らしいソリューションとは思えません。私は確かにそれについて直面して最初のものではないので、これにいくつかのすぐに使用できるソリューションがあったかどうか私は思った。 – jb90

+1

必ずしも完璧な解決策ではありませんが、処理を行う方が良いですし、 'req.sessionStore.reload(callback_function)'とコールバック関数を呼び出してセッションを変更し、直ちに 'res.send'を呼び出してください。最善の解決策は、通信チャネル(UNIXソケット、Redis)を持ち、セッションを変更しているときに(つまり、msg: 'session:id locked'のロックをシミュレートする)通知を送信し、応答を送信するときです別のメッセージ( 'session:id unlocked')をトリガーします。すべてのreqはリッスンし、ロックされている場合はセッションを変更しないでください(ロックされていないリロードセッションの場合)。 – alessioalex

+0

あなたの助けていただきありがとうございます:)私はより良い解決策を見つけられるまで試してみましょう。 – jb90

関連する問題