我最近将我的Node应用程序转换为在我的本地计算机上运行,使用Amazon EC2作为Node应用程序,使用VPN作为文件服务和MySQL。
我很好地了解了Promises使用 Bluebird 编写以下连接代码段(在响应客户端之前运行3个查询)。连接在我的机器上运行,但是使用VPN托管的MySQL设置,连接每次都崩溃,大约在应用程序启动后30秒,我意识到可能是因为我忘了关闭它们。
编辑:根据评论,似乎问题不在连接闭包中。
所以我以最熟悉的方式修改了我的脚本来关闭连接,但是使用Promises,这很令人困惑。此版本的连接不起作用。 它不会失败或导致任何错误。它只是在服务器端返回没有结果。我认为我的问题与我关闭连接的方式有关。
造成这个问题的原因是什么?
这是连接关闭吗?
如果是这样,我该如何正确关闭它们?
var mysql = require('mysql');
var Promise = require('bluebird');
var moment = require('moment');
function createConnection() {
var connection = mysql.createConnection({
dateStrings : true,
host : 'hostname',
user : 'username',
password : 'password',
database : 'database'
});
connection = Promise.promisifyAll(connection);
return connection;
}
function sendGame(req, res, sales, settings, categories, players) {
var game = new Object();
game.sales = sales;
game.players = players;
game.settings = settings;
game.categories = categories;
var JSONgame = JSON.stringify(game);
console.log("Game: " + JSON.stringify(game, undefined, 4));
}
var retrieveSales = Promise.method(function (username, connection, timeFrame) {
console.log('User ' + username + ' retrieving sales...');
var q = 'select * from sales_entries where date BETWEEN ? AND ?';
return connection.queryAsync(q, timeFrame).then(function (results) {
return results[0];
});
});
var retrieveSettings = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving settings...');
var q = 'select * from sales_settings';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrieveCategories = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving categories...');
var q = 'select * from sales_categories';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var retrievePlayers = Promise.method(function (username, connection) {
console.log('User ' + username + ' retrieving players...');
var q = 'select * from users';
return connection.queryAsync(q).then(function (results) {
return results[0];
});
});
var gameSucceed = Promise.method(function gameSucceed(req, res) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
//var connection = Promise.promisifyAll(createConnection());
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}).then(function () {
connection.end(),
console.log("...Connection with the MySQL database for Game retrieval ended")
});
});
function getGameData(req, res) {
gameSucceed(req, res).spread(function (sales, settings, categories, players) {
return sendGame(req, res, sales, settings, categories, players);
});
};
var req = new Object();
var res = new Object();
req.body = {
"username" : "user123",
"password" : "password"
}
getGameData(req, res);
User user123 retrieving game...
Connection with the MySQL database openned for Game retrieval...
User user123 retrieving sales...
User user123 retrieving settings...
User user123 retrieving categories...
User user123 retrieving players...
...Connection with the MySQL database for Game retrieval ended
Game: {}
答案 0 :(得分:1)
var gameSucceed = function gameSucceed(req, res) { … var connection = createConnection()); return connection.connectAsync().then(function () { return Promise.all([…]); }).then(function () { connection.end(); }); };
最终从此方法返回的承诺没有分辨率值。它是由then
来自其return
的回调的调用创建的 - 这将导致undefined
。要解决此问题,只需将结果路由到:
.then(function(results) {
connection.end();
return results;
});
但是,如果您这样做,则在发生错误时不会关闭连接。最好的解决方案是使用finally()
method,它就像同步代码中的finally
子句一样。它的回调将被用于解决和拒绝,并且由此产生的承诺将自动继承该值。
.finally(function() {
connection.end();
})
// .then(function(results) { })
答案 1 :(得分:0)
您的代码有一个特殊的资源管理问题,就像Bergi所说的那样。您必须记住何时关闭集合以及何时不关闭集合。
最佳解决方案是使用Promise.using
但是,这只能在Bluebird的v2分支中使用,因此您将不得不等待一段时间。
在此之前,您可以创建自己的包装器方法,以执行更基本的范围资源管理:
function connect(fn,timeout){
timeout = (timeout === undefined) ? 8000 : timeout; // connection timeout
return createConnection().then(function(connection){
// run the function, when it resolves - close the connection
// set a 7 second timeout on the connection
return fn(connection).timeout(timeout).finally(function(){
connection.end();
});
});
}
可以让你这样做:
connect(function(connection){
return gameSucceed(req,resp,connection); // connection is injected to that fn now
}).then(function(val){
// gameSucceed resolution value here
});
现在,当gameSucceed
完成后,连接将自动关闭。这会使gameSucceed
本身看起来像:
var gameSucceed = Promise.method(function gameSucceed(req, res,connection) {
var username = req.body.username;
console.log('User ' + req.body.username + ' retrieving game...');
var timeFrame = [moment().days(0).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss"), moment().days(6).hour(0).minute(0).second(0).format("YYYY-MM-DD HH:mm:ss")];
return connection.connectAsync().then(function () {
console.log('Connection with the MySQL database openned for Game retrieval...');
return Promise.all([retrieveSales(username, connection, timeFrame), retrieveSettings(username, connection), retrieveCategories(username, connection), retrievePlayers(username, connection)]);
}); // no longer its responsibility to handle the connection
});
通常,您可能还需要为代码考虑更多OOPish编码风格。
祝你好运,编码愉快。