我有一个连接到postgres db(node-postgres模块v2.1.0)的nodeJS(v.0.10.23)代理,以及返回各种json数据的pgpool-II。
在当天,这就是处理连接错误的方法:
var after = function(callback) {
return function(err, queryResult) {
if(err) {
response.writeHead(500, _header);
console.log("ERROR: 500");
console.log(err);
return response.end(JSON.stringify({error: err}));
}
callback(queryResult)
}
};
基本上它的作用是在没有错误的情况下消耗响应。
可以在此处找到深入解释:Node js - http.request() problems with connection pooling
使用上面的功能,我有这样的事情:
pg.connect(_conString, after(function(err, client, done) {
client.query(sql, after(function(result) {
...
done();
}
由于当函数传递给after()s回调时上下文丢失,我失去了使用pg.connect()传递的固有done()方法的能力。
删除之后解决问题,但随后,在适当的时候,并且有相当数量的客户端提取数据,节点将一直挂起,直到它被重置。
是否有不同的方式来消费各种异步响应?
或者可能是将pg.connect上下文传递给回调的方法?
答案 0 :(得分:2)
嗯,当然你丢失了done()
,你永远不会在你的after()
函数中将第三个参数传递给你的回调。
function after(cb) {
return function() {
// you're using this function in a context where the arguments
// passed in could be anything. the only constant is that the first
// argument is the error, if any
if (arguments[0]) {
response.writeHead(500, _header);
console.log("ERROR: 500");
console.log(err);
return response.end(JSON.stringify({error: arguments[0]}));
}
// apply the entire argument list to the callback, without modification
cb.apply(cb, arguments);
};
}
...这也修复了通过client
变量传递queryResult
的可疑惯例。
答案 1 :(得分:0)
查看最后一个示例(使用工厂函数并传递响应) 使用工厂函数非常有趣,因为它可以节省代码
app.get('/parallel',function(request,response,next){
function err(err)
{
console.log(err.stack);
response.end('error'+err.stack);
}
function send(data)
{
response.end(JSON.stringify(data))
}
pg.connect(config, function(err, client, done) {
if(err){done();return err(err);}
client.query("SELECT * FROM NOW()", function(err, result) {
done();
if(err){return err (err);}
send(result);
}, 0)
})
})
你可以尝试使用colan的async来选择。
npm install async
// an example using an object instead of an array
var x1=null;
async.series({// in javascript the creation order is preserved in Object.keys
one: function(callback){
setTimeout(function(){
x1=3;
callback(null, 1);
}, 200);
},
two: function(callback){
console.log('select where x1='+x1);
setTimeout(function(){
callback(null, 2);
}, 100);
}
},
function(err, results) {// called instantly if there is an error
// results is now equal to: {one: 1, two: 2}
});
单选工厂回调
function makesenderr(response){
return function senderr(err,ok)
{
console.log(err.stack);
response.end('error'+err.stack);
}
}
function makesendjson(response){
return function sendjson(data)
{
response.end(JSON.stringify(data))
}
}
function tryconn(err,ok){
return function(errarg, client, done) {
if(errarg){done();return err(errarg);}
ok(client,done);
}
}
function doneerrok(done,err,ok){
return function(errarg, result) {
done();
if(errarg){return err(errarg);}
ok(result);
}
}
var async=require('async')
app.get('/foo',function(request,response,next){
var senderr=makesenderr(response)
var sendjson=makesendjson(response)
pg.connect(config, tryconn(senderr,function(client,done){
client.query("SELECT one FROM t1",doneerrok(done,senderror,sendjson), 0)
}))
})
使用工厂功能并传递响应
function senderr(response,err)
{//add headers here
console.log(err.stack);
response.end('error'+err.stack);
}
function sendjson(response,data)
{//add headers here
response.end(JSON.stringify(data))
}
function tryconn(response,ok){
return function(err, client, done) {
if(err){done();return senderr(response,err);}
ok(client,done);
}
}
function donerespok(done,response,ok){
return function(err, result) {
done();
if(err){return err(response,err);}
ok(response,result);
}
}
function respok(response,ok){
return function(err, result) {
done();
if(err){return err(response,err);}
ok(response,result);
}
}
function donecb(done,cb){ return function(){done();cb.apply(this,arguments);} }
var async=require('async')
app.get('/foo',function(request,response,next){
pg.connect(config, tryconn(response,function(client,done){
client.query("SELECT one FROM t1",donerespok(done,response,sendjson), 0)
}))
})
app.get('/series',function(request,response,next){
pg.connect(config, tryconn(response,function(client,done){
var one={};
async.series({
one: function(cb){
client.query("SELECT one FROM t1", function(err, result) {
one=result;cb(err,result);
}, 0)
},
two: function(cb){
client.query("SELECT two FROM t2 where one="+one[0].one,cb, 0)
}
}, // results is now equal to: {one: [{one:1}], two: [{two:2},{two:2}]}
donerespok(done,response,sendjson) );
}))
})
app.get('/parallel',function(request,response,next){
async.parallel({
one: function(cb){
pg.connect(config, tryconn(response,function(client,done){
client.query("SELECT one FROM t1",donecb(done,cb), 0)
}))
},
two: function(cb){
pg.connect(config, tryconn(response,function(client,done){
client.query("SELECT two FROM t2",donecb(done,cb), 0)
}))
}
}, // results is now equal to: {one: [{one:1},{one:2}], two: [{two:1},{two:2}]}
respok(response,sendjson) );
})
答案 2 :(得分:0)
首先,你应该增加你的连接池,如果你还没有,这看起来像你不想要限制为6个连接。您还应该在请求上设置相当低的超时。
至于数据的上下文,您是否考虑将pg.connect的this
绑定到after函数?这将允许您在本地环境中完成访问。
pg.connect(_conString, after(function(err, client, done) {
this.done = done;
client.query(sql, (after(function(result) {
...
this.done();
}).bind(this));
});
Smashing杂志上有一篇关于几天前bind()
使用{{1}}的好文章here