NodeJS在多个请求后无限期挂起

时间:2014-01-19 14:06:24

标签: sql node.js postgresql asynchronous callback

我有一个连接到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上下文传递给回调的方法?

3 个答案:

答案 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