Skip to content
This repository has been archived by the owner on May 10, 2019. It is now read-only.

update database code and mysql driver to handle stalled connections #1211

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lib/browserid/fake_verification.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ const
configuration = require('../configuration.js'),
url = require('url'),
db = require('../db.js');
logger = require('../logging.js').logger;
logger = require('../logging.js').logger,
wsapi = require('../wsapi');

logger.warn("HEAR YE: Fake verfication enabled, aceess via /wsapi/fake_verification?email=foo@bar.com");
logger.warn("THIS IS NEVER OK IN A PRODUCTION ENVIRONMENT");

exports.addVerificationWSAPI = function(app) {
app.get('/wsapi/fake_verification', function(req, res) {
var email = url.parse(req.url, true).query['email'];
db.verificationSecretForEmail(email, function(secret) {
db.verificationSecretForEmail(email, function(err, secret) {
if (err) return wsapi.databaseDown(resp, err);
if (secret) res.write(secret);
else res.writeHead(400, {"Content-Type": "text/plain"});
res.end();
Expand Down
11 changes: 10 additions & 1 deletion lib/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ var conf = module.exports = convict({
env: 'DATABASE_NAME'
},
password: 'string?',
host: 'string?'
host: 'string?',
max_query_time_ms: {
format: 'integer = 5000',
doc: "The maximum amount of time we'll allow a query to run before considering the database to be sick",
env: 'MAX_QUERY_TIME_MS'
},
max_reconnect_attempts: {
format: 'integer = 1',
doc: "The maximum number of times we'll attempt to reconnect to the database before failing all outstanding queries"
}
},
smtp: {
host: 'string?',
Expand Down
2 changes: 1 addition & 1 deletion lib/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ exports.open = function(cfg, cb) {
ready = true;
waiting.forEach(function(f) { f() });
waiting = [];
if (cb) cb();
if (cb) cb(null);
}
});
};
Expand Down
59 changes: 29 additions & 30 deletions lib/db/json.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,41 +81,40 @@ exports.open = function(cfg, cb) {
logger.debug("opening JSON database: " + dbPath);

sync();

setTimeout(cb, 0);
process.nextTick(function() { cb(null); });
};

exports.closeAndRemove = function(cb) {
// if the file cannot be removed, it's not an error, just means it was never
// written or deleted by a different process
try { fs.unlinkSync(dbPath); } catch(e) { }
setTimeout(function() { cb(undefined); }, 0);
process.nextTick(function() { cb(null); });
};

exports.close = function(cb) {
// don't flush database here to disk, the database is flushed synchronously when
// written - If we were to flush here we could overwrite changes made by
// another process - see issue #557
setTimeout(function() { cb(undefined) }, 0);
process.nextTick(function() { cb(null) });
};

exports.emailKnown = function(email, cb) {
sync();
var m = jsel.match(".emails ." + ESC(email), db.users);
setTimeout(function() { cb(m.length > 0) }, 0);
process.nextTick(function() { cb(null, m.length > 0) });
};

exports.emailType = function(email, cb) {
sync();
var m = jsel.match(".emails ." + ESC(email), db.users);
process.nextTick(function() { cb(m.length ? m[0].type : undefined); });
process.nextTick(function() { cb(null, m.length ? m[0].type : undefined); });
};

exports.isStaged = function(email, cb) {
if (cb) {
setTimeout(function() {
sync();
cb(db.stagedEmails.hasOwnProperty(email));
cb(null, db.stagedEmails.hasOwnProperty(email));
}, 0);
}
};
Expand All @@ -127,15 +126,15 @@ exports.lastStaged = function(email, cb) {
if (db.stagedEmails.hasOwnProperty(email)) {
d = new Date(db.staged[db.stagedEmails[email]].when);
}
setTimeout(function() { cb(d); }, 0);
setTimeout(function() { cb(null, d); }, 0);
}
};

exports.emailsBelongToSameAccount = function(lhs, rhs, cb) {
sync();
var m = jsel.match(".emails:has(."+ESC(lhs)+"):has(."+ESC(rhs)+")", db.users);
process.nextTick(function() {
cb(m && m.length == 1);
cb(null, m && m.length == 1);
});
};

Expand All @@ -145,15 +144,15 @@ exports.emailToUID = function(email, cb) {
if (m.length === 0) m = undefined;
else m = m[0];
process.nextTick(function() {
cb(m);
cb(null, m);
});
};

exports.userOwnsEmail = function(uid, email, cb) {
sync();
var m = jsel.match(":root > object:has(:root > .id:expr(x=" + ESC(uid) + ")):has(.emails > ." + ESC(email) + ")", db.users);
process.nextTick(function() {
cb(m && m.length == 1);
cb(null, m && m.length == 1);
});
};

Expand All @@ -172,7 +171,7 @@ function addEmailToAccount(userID, email, type, cb) {
emails[0][email] = { type: type };
flush();
}
cb();
cb(null);
});
}

Expand All @@ -187,7 +186,7 @@ exports.stageUser = function(email, cb) {
};
db.stagedEmails[email] = secret;
flush();
setTimeout(function() { cb(secret); }, 0);
process.nextTick(function() { cb(null, secret); });
});
};

Expand All @@ -204,7 +203,7 @@ exports.stageEmail = function(existing_user, new_email, cb) {
db.stagedEmails[new_email] = secret;
flush();

setTimeout(function() { cb(secret); }, 0);
process.nextTick(function() { cb(null, secret); });
});
};

Expand All @@ -219,14 +218,14 @@ exports.createUserWithPrimaryEmail = function(email, cb) {
});
flush();
process.nextTick(function() {
cb(undefined, uid);
cb(null, uid);
});
};

exports.haveVerificationSecret = function(secret, cb) {
process.nextTick(function() {
sync();
cb(!!(db.staged[secret]));
cb(null, !!(db.staged[secret]));
});
};

Expand All @@ -235,8 +234,8 @@ exports.emailForVerificationSecret = function(secret, cb) {
process.nextTick(function() {
sync();
if (!db.staged[secret]) return cb("no such secret");
exports.checkAuth(db.staged[secret].existing_user, function (hash) {
cb(undefined, {
exports.checkAuth(db.staged[secret].existing_user, function (err, hash) {
cb(err, {
email: db.staged[secret].email,
needs_password: !hash
});
Expand All @@ -247,7 +246,7 @@ exports.emailForVerificationSecret = function(secret, cb) {
exports.verificationSecretForEmail = function(email, cb) {
setTimeout(function() {
sync();
cb(db.stagedEmails[email]);
cb(null, db.stagedEmails[email]);
}, 0);
};

Expand All @@ -261,7 +260,7 @@ exports.gotVerificationSecret = function(secret, hash, cb) {
delete db.stagedEmails[o.email];
flush();
if (o.type === 'add_account') {
exports.emailKnown(o.email, function(known) {
exports.emailKnown(o.email, function(err, known) {
function createAccount() {
var emailVal = {};
emailVal[o.email] = { type: 'secondary' };
Expand All @@ -272,7 +271,7 @@ exports.gotVerificationSecret = function(secret, hash, cb) {
emails: emailVal
});
flush();
cb(undefined, o.email, uid);
cb(null, o.email, uid);
}

// if this email address is known and a user has completed a re-verification of this email
Expand All @@ -291,7 +290,7 @@ exports.gotVerificationSecret = function(secret, hash, cb) {
}
});
} else if (o.type === 'add_email') {
exports.emailKnown(o.email, function(known) {
exports.emailKnown(o.email, function(err, known) {
function addIt() {
addEmailToAccount(o.existing_user, o.email, 'secondary', function(e) {
cb(e, o.email, o.existing_user);
Expand All @@ -313,7 +312,7 @@ exports.gotVerificationSecret = function(secret, hash, cb) {

exports.addPrimaryEmailToAccount = function(userID, emailToAdd, cb) {
sync();
exports.emailKnown(emailToAdd, function(known) {
exports.emailKnown(emailToAdd, function(err, known) {
function addIt() {
addEmailToAccount(userID, emailToAdd, 'primary', cb);
}
Expand All @@ -336,15 +335,15 @@ exports.checkAuth = function(userID, cb) {
if (m.length === 0) m = undefined;
else m = m[0];
}
process.nextTick(function() { cb(m) });
process.nextTick(function() { cb(null, m) });
};

exports.userKnown = function(userID, cb) {
sync();
var m = jsel.match(":root > object:has(:root > .id:expr(x=" + ESC(userID) + "))", db.users);
if (m.length === 0) m = undefined;
else m = m[0];
process.nextTick(function() { cb(m) });
process.nextTick(function() { cb(null, m) });
};

exports.updatePassword = function(userID, hash, cb) {
Expand Down Expand Up @@ -378,7 +377,7 @@ exports.removeEmail = function(authenticated_user, email, cb) {
delete emails[email];
flush();
}
setTimeout(function() { cb(); }, 0);
setTimeout(function() { cb(null); }, 0);
};

function removeEmailNoCheck(email, cb) {
Expand All @@ -389,7 +388,7 @@ function removeEmailNoCheck(email, cb) {
delete emails[email];
flush();
}
process.nextTick(function() { cb(); });
process.nextTick(function() { cb(null); });
};

exports.cancelAccount = function(authenticated_uid, cb) {
Expand All @@ -405,7 +404,7 @@ exports.cancelAccount = function(authenticated_uid, cb) {
flush();
}

process.nextTick(function() { cb(); });
process.nextTick(function() { cb(null); });
};

exports.addTestUser = function(email, hash, cb) {
Expand All @@ -419,10 +418,10 @@ exports.addTestUser = function(email, hash, cb) {
emails: emailVal
});
flush();
cb();
cb(null);
});
};

exports.ping = function(cb) {
setTimeout(function() { cb(); }, 0);
process.nextTick(function() { cb(null); });
};
Loading