NodeJS在多次请求后无限期地挂起
我有一个nodeJS(v.0.10.23)代理连接到postgres数据库(node-postgres模块v2.1.0),以及返回各种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) } };
基本上它所做的是在没有错误的情况下消耗响应。
可以在这里find一个深入的解释: Node js – http.request()连接池的问题
使用上面的函数,我有这样的东西:
pg.connect(_conString, after(function(err, client, done) { client.query(sql, after(function(result) { ... done(); }
由于当函数传递到after()scallback函数时上下文丢失了,所以我放弃了使用pg.connect()传递的先天done()方法的能力。
删除后解决了这个问题,但随后,在适当的时间,并有相当数量的客户端拉数据,节点将挂起,直到它被重置。
是否有消耗各种asynchronous响应的不同方式?
或者可能是一种将pg.connect上下文传递给callback的方法?
那么,当然,你失去了done()
,你永远不会在你的after()
函数中传递第三个参数给你的callback函数。
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); }; }
…这也解决了通过queryResult
variables传递client
的可疑约定。
看到最后一个例子(使用工厂函数和传递响应),使用工厂函数是非常有趣的,因为它节省了代码
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) }) })
你可以尝试使用可乐的asynchronous到select。
npm安装asynchronous
// 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} });
单选工厂的callback
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和传递响应
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) ); })
首先,你应该增加你的连接池,如果你还没有,这看起来像你不想限制6个连接。 你也应该设置一个相当低的请求超时。
至于数据的上下文,你有没有考虑绑定pg.connect的this
到后函数? 这将允许您在本地上下文中进行访问。
pg.connect(_conString, after(function(err, client, done) { this.done = done; client.query(sql, (after(function(result) { ... this.done(); }).bind(this)); });
粉碎杂志有一个很好的文章,在前几天使用bind()
在这里