2011-12-14 38 views
5

Trong một dự án hiện tại (loại một hệ thống cửa hàng), tôi sử dụng Node.js với expressJSkết nối-Mongo như cửa hàng phiên. Về phía máy khách, tôi sử dụng một yêu cầu duy nhất lúc khởi động để tạo một phiên mới và gửi nhiều yêu cầu song song đến máy chủ node.js sau đó. Vì các yêu cầu song song này thay đổi phiên, những thay đổi đó dường như ghi đè lên nhau, mặc dù chúng thay đổi các đối tượng khác nhau của phiên, tất nhiên.yêu cầu song song với Node.js, kết nối-Mông Cổ, phiên ghi đè

Ví dụ (tất cả 3 yêu cầu bắt đầu cùng một lúc):

  • Request Một đẩy một số sản phẩm đến các mảng req.session.productHist['abc']
  • Yêu cầu B đẩy sản phẩm để req.session.productHist['def']
  • Yêu cầu C mất một thời gian, nhưng không thay đổi phiên

Vì yêu cầu C hoàn tất sau khi yêu cầu A và B, nhưng bắt đầu trước khi kết thúc, có vẻ như ghi đè session.productHist với giá trị được giữ khi yêu cầu C bắt đầu (null).

Làm cách nào để khắc phục sự cố này?

Cập nhật:

Một số mã ví dụ với giao diện điều khiển đầu ra: log

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

Console:

máy chủ bắt đầu tại địa chỉ: Thu, 15 Tháng mười hai 2011 15:50:37 GMT

################### newSession
#################### init bắt đầu
################### sản phẩm -1 bắt đầu

sản phẩm: session.productHist: {"-1": [{"id": "Thu, 15 Dec 2011 15:50:40 GMT"}, {"id": "Thu, 15 Dec 2011 15:50:40 giờ "}]}

################### sản phẩm -1 cuối


init: session.productHist: {}

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


[...]

sản phẩm ################### -1 bắt đầu

sản phẩm: session.productHist: { "-1": [{ "id": "Thu, 15 Dec 2011 15:50:53 GMT"}, {"id": "Thu, 15 Dec 2011 15:50:53 GMT"}]}

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

Không thể yêu cầu C xảy ra sau khi A & B? – alessioalex

+0

Tôi muốn có thể gửi các yêu cầu song song nếu có thể. tôi có thể gửi A & B sau khi C hoàn thành, nhưng điều đó sẽ làm chậm trải nghiệm người dùng – jb90

+0

Yêu cầu C làm gì ..? – alessioalex

Trả lời

3

Tôi nghĩ rằng tôi đã tìm thấy câu trả lời cho vấn đề phức tạp này.

Từ các tài liệu Express.js:

Properties on req.session are automatically saved on a response

phiên bản ngắn

Khi bạn thiết lập một biến phiên (req.session.my_var = value), nó không thực sự lưu sau đó (tại thời điểm đó chính xác), nhưng sau đó (khi bạn gửi phản hồi, trong trường hợp của bạn là khi bạn làm res.send). Điều đó gây ra vấn đề của bạn.

Long phiên bản

Vậy điều đó có nghĩa là chính xác?

  1. Bạn thực hiện một yêu cầu, sau đó nhận được các biến session (mà ở trạng thái A) và sau đó làm điều gì đó với nó (đòi hỏi một thời gian)
  2. Bạn thực hiện một yêu cầu khác và nhận được sự biến session (mà vẫn đang ở trạng thái A vì phản hồi vẫn chưa được gửi) và thay đổi một số nội dung sang số
  3. Bây giờ, quá trình xử lý phiên đã được thực hiện để bạn gửi phản hồi từ 1), do đó sửa đổi biến phiên và đưa nó vào bang B
  4. Đây là phần 'vui', sau khi bạn gửi phản hồi từ 2). Bây giờ bạn không thực sự sửa đổi phiên hiện tại (đã được cập nhật vào trạng thái B), vì phản hồi bị trì hoãn, vì vậy những gì bạn đang thực sự thay đổi là phiên từ trạng thái A, đưa nó vào trạng thái C => có nghĩa là tất cả những sửa đổi từ tiểu bang B đã bị mất!
+0

Tôi nghĩ rằng đây là vấn đề, nhưng bạn có một giải pháp cho điều đó? Tôi đoán tôi có thể phản chiếu toàn bộ phiên trong bộ nhớ node.js nhưng không có gì tôi nghĩ là một giải pháp tốt, vì nó sẽ khiến bộ nhớ mongo không cần thiết đến một điểm nhất định (và tạo ra một chi phí lớn). Tôi tự hỏi nếu có một số giải pháp sẵn sàng sử dụng cho điều này vì tôi chắc chắn không phải là người đầu tiên vấp ngã về điều đó. – jb90

+1

Không nhất thiết phải là một giải pháp hoàn hảo, nhưng tốt hơn là bạn nên xử lý, sau đó gọi 'req.sessionStore.reload (callback_function)' và trong hàm gọi lại để thay đổi phiên và ngay lập tức gọi 'res.send'. Giải pháp tốt nhất là có một kênh giao tiếp (ổ cắm UNIX, Redis) và gửi thông báo khi bạn thay đổi phiên (do đó mô phỏng một khóa, ví dụ: phiên: id bị khóa) và khi bạn gửi trả lời để kích hoạt một thông báo khác ('session: id unlocked'). Mỗi req nên được lắng nghe và không sửa đổi phiên nếu bị khóa (trên 'tải lại' mở phiên). – alessioalex

+0

Cảm ơn bạn đã giúp đỡ của bạn :) Tôi sẽ cung cấp cho rằng một thử cho đến khi tôi tìm thấy một giải pháp tốt hơn (nếu tôi tìm thấy một). – jb90

Các vấn đề liên quan