在本地测试好的nodejs应用部署到百度BAE上出现no open connections问题,没有打开的数据库连接,出现这个错误的原因是百度共享mongodb不支持长连接,每隔30秒就会断开,后来就想到断开重连的方式,经过网上查阅,确实有前人是这么做的,自己写的方法不行就用别人的,可是这个问题依旧,反复的折腾就是解决不了,开始怀疑自己的智商。为什么别人的可以连上就我的不行,期间用抛出异常的方式强制应用重启,这样只是治标不治本,还会有一分钟的重启时间不能访问。最后只好一步步测试,每一句代码都输出一下,在BAE上部署后发现连接确实有打开的,可是为什么应用还会报错,看了下错误信息,发现这个错误时有关session的,恍然大悟,我的session用的是mongodb作为存储,它也会断开,但是没有重连机制,所以就一直报错。
既然找到问题所在,那就解决吧,可是请看以下代码:
app.use(session({ secret:settings.cookieSecret, store:newMongoStore({ url:"mongodb://"+settings.uid+":"+settings.pwd+"@"+settings.host+":"+settings.port+"/"+settings.db }) }));
Using custom connection
var mongoose = require("mongoose"); mongoose.connect("mongodb://localhost/mysessionstore"); varSessionStore= require("session-mongoose")(express); var store =newSessionStore({ interval:120000,// expiration check worker run interval in millisec (default: 60000) connection: mongoose.connection // <== custom connection });
正好用的是mongoose,那我就把重连机制的mongoose变量传过来,并安装
session-mongosse,
结果又是一个坑,
session-mongosse要求的connect版本是2.0的,而我安装的是3.0以上的,我不可能降低版本来适应它吧,这样会导致其他依赖出现问题。还是使用原来的
connect-mongo中间件好了,看了一下connect-mongo的文档和源码,有这么一个选项:
mongoose_connection
in the form:
someMongooseDb.connections[0]
to use an existing mongoose connection. (optional)
这个用的正好也是mongoose连接,那就好办了
var store =newMongoStore({ // url:"mongodb://"+settings.uid+":"+settings.pwd+"@"+settings.host+":"+settings.port+"/"+settings.db, interval:120000,// expiration check worker run interval in millisec (default: 60000) mongoose_connection: connection.mongoose.connection // <== custom connection }); app.use(session({ secret:settings.cookieSecret, store:store, resave:false, saveUninitialized:false }));
在MongoStore属性中添加mongoose_connection属性,值为mongoose,这样的话session的连接用的也是查询的,完美解决。
顺带贴上重连机制代码:getConnect.js
/** * Created by huopanpan on 2014/6/30. */ /** * 连接到mongodb * 使用mongoose而非mongodb中间件 **/ var mongoose = require('mongoose'); var host ="mongo.duapp.com", port ="8908", username ="", password ="", dbName ="", url ="mongodb://"+ username +":"+ password +"@"+ host +":"+ port +"/"+ dbName; var recon =true; function getConnect(){ var opts ={ db:{ native_parser:true }, server:{ poolSize:5, auto_reconnect:true }, user: username, pass: password }; // mongoose.connect("mongodb://HahMqSkZWUq9QWHsWceXmG83:XH82hOf5MGzoMUMUkCNj0KdBvecF3mzP@mongo.duapp.com:8908/pQPzvWlctdHpUjrbtFnX");//需要验证账户 // mongoose.connect("mongodb://" + username + ":" + password +"@"+ host + ":" + port + "/" + dbName);//需要验证账户 mongoose.connect(url, opts); var dbcon = mongoose.connection; // var dbcon = mongoose.createConnection(url, opts); dbcon.on('error',function(error){ console.log('connection error'); // throw new Error('disconnected,restart'); dbcon.close(); }); //监听关闭事件并重连 dbcon.on('disconnected',function(){ console.log('disconnected'); dbcon.close(); }); dbcon.on('open',function(){ console.log('connection success open'); recon =true; }); dbcon.on('close',function(err){ console.log('closed'); // dbcon.open(host, dbName, port, opts, function() { // console.log('closed-opening'); // }); reConnect('*'); }); function reConnect(msg){ console.log('reConnect'+msg); if(recon){ console.log('reConnect-**'); dbcon.open(host, dbName, port, opts,function(){ console.log('closed-opening'); }); recon =false; console.log('reConnect-***'); }; console.log('reConnect-end'); } } exports.getConnect = getConnect;//包含到module.exports对象中, // 如果module.exports中包含属性或方法则export.XX将被忽略 // Module.exports才是真正的接口,exports只不过是它的一个辅助工具。 // 最终返回给调用的是Module.exports而不是exports。 // 所有的exports收集到的属性和方法,都赋值给了Module.exports。 // 当然,这有个前提,就是Module.exports本身不具备任何属性和方法。 // 如果,Module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。 //module.exports = getConnection;//直接导出这个对象 exports.mongoose = mongoose;
将mongoose导出供session公用
补充:以上内容理论上解决了问题,但实际还有其他问题需要解决,请查看后续的两篇: