From 6a86da316bc310f295d4af72ce1362bb0c78bef2 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Mon, 3 Feb 2014 17:05:18 -0700 Subject: [PATCH] chore(mongoose): set some options per #2725 to address high number of open connections, replset connection timeout, and close mongoose connection on process death --- src/models/challenge.js | 1 - src/models/group.js | 3 --- src/server.js | 21 ++++++++++++--------- src/utils.js | 29 ++++++++--------------------- 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/models/challenge.js b/src/models/challenge.js index 2656bebe1b..a01cea9575 100644 --- a/src/models/challenge.js +++ b/src/models/challenge.js @@ -3,7 +3,6 @@ var Schema = mongoose.Schema; var shared = require('habitrpg-shared'); var _ = require('lodash'); var TaskSchemas = require('./task'); -var Group = require('./group').model; var ChallengeSchema = new Schema({ _id: {type: String, 'default': shared.uuid}, diff --git a/src/models/group.js b/src/models/group.js index fa901dad8f..f3b3cad8e5 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -3,7 +3,6 @@ var Schema = mongoose.Schema; var shared = require('habitrpg-shared'); var _ = require('lodash'); var async = require('async'); -var User = require('./user').model; var GroupSchema = new Schema({ _id: {type: String, 'default': shared.uuid}, @@ -161,8 +160,6 @@ GroupSchema.methods.finishQuest = function(quest, cb) { }) var members = _.keys(group.quest.members); group.quest = {};group.markModified('quest'); - // FIXME this is TERRIBLE practice. Looks like there are circular dependencies in the models, such that `var User` at - // this point is undefined. So we get around that by loading from mongoose only once we get to this point mongoose.models.User.update({_id:{$in:members}}, updates, {multi:true}, cb); } diff --git a/src/server.js b/src/server.js index aa734c7d3a..81ffb155d4 100644 --- a/src/server.js +++ b/src/server.js @@ -35,14 +35,18 @@ if (cluster.isMaster && (isDev || isProd)) { // ------------ MongoDB Configuration ------------ mongoose = require('mongoose'); - require('./models/user'); //load up the user schema - TODO is this necessary? - require('./models/group'); - require('./models/challenge'); - mongoose.connect(nconf.get('NODE_DB_URI'), {auto_reconnect:true}, function(err) { - if (err) throw err; - logging.info('Connected with Mongoose'); + var mongooseOptions = !isProd ? {} : { + replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }, + server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } } + }; + mongoose.connect(nconf.get('NODE_DB_URI'), mongooseOptions, function(err) { + if (err) throw err; + logging.info('Connected with Mongoose'); }); - + // load schemas & models + require('./challenge'); + require('./group'); + require('./user'); // ------------ Passport Configuration ------------ var passport = require('passport') @@ -63,7 +67,6 @@ if (cluster.isMaster && (isDev || isProd)) { done(null, obj); }); - // Use the FacebookStrategy within Passport. // Strategies in Passport require a `verify` function, which accept // credentials (in this case, an accessToken, refreshToken, and Facebook @@ -135,7 +138,7 @@ if (cluster.isMaster && (isDev || isProd)) { app.use('/api/v1', require('./routes/apiv1').middleware); app.use('/export', require('./routes/dataexport').middleware); - app.use(utils.crashWorker(server)); + app.use(utils.crashWorker(server,mongoose)); app.use(utils.errorHandler); require('./routes/apiv2.coffee')(swagger, v2); diff --git a/src/utils.js b/src/utils.js index 4ff8f2a895..1fb45587af 100644 --- a/src/utils.js +++ b/src/utils.js @@ -6,10 +6,10 @@ var cluster = require("cluster"); module.exports.sendEmail = function(mailData) { var smtpTransport = nodemailer.createTransport("SMTP",{ - service: nconf.get('SMTP_SERVICE'), + service: nconf.get('SMTP_SERVICE'), auth: { - user: nconf.get('SMTP_USER'), - pass: nconf.get('SMTP_PASS') + user: nconf.get('SMTP_USER'), + pass: nconf.get('SMTP_PASS') } }); smtpTransport.sendMail(mailData, function(error, response){ @@ -33,8 +33,6 @@ module.exports.makeSalt = function() { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len); } - - /** * Load nconf and define default configuration values if config.json or ENV vars are not found */ @@ -44,25 +42,13 @@ module.exports.setupConfig = function(){ //.file('defaults', path.join(path.resolve(__dirname, '../config.json.example'))) .file('user', path.join(path.resolve(__dirname, '../config.json'))); -// var agent; -// if (process.env.NODE_ENV === 'development') { -// // Follow these instructions for profiling / debugging leaks -// // * https://developers.google.com/chrome-developer-tools/docs/heap-profiling -// // * https://developers.google.com/chrome-developer-tools/docs/memory-analysis-101 -// agent = require('webkit-devtools-agent'); -// var logging = require('./logging'); -// logging.info("To debug memory leaks:" + -// "\n\t(1) Run `kill -SIGUSR2 " + process.pid + "`" + -// "\n\t(2) open http://c4milo.github.com/node-webkit-agent/21.0.1180.57/inspector.html?host=localhost:1337&page=0"); -// } - - if (nconf.get('NODE_ENV') === "development") { + if (nconf.get('NODE_ENV') === "development") Error.stackTraceLimit = Infinity; - } - if (nconf.get('NODE_ENV') === 'production') require('newrelic'); + if (nconf.get('NODE_ENV') === 'production') + require('newrelic'); }; -module.exports.crashWorker = function(server) { +module.exports.crashWorker = function(server,mongoose) { return function(err, req, res, next) { if (!cluster.isMaster) { // make sure we close down within 30 seconds @@ -73,6 +59,7 @@ module.exports.crashWorker = function(server) { killtimer.unref(); // stop taking new requests. server.close(); + mongoose.connection.close(); cluster.worker.disconnect(); } next(err);