From 6b776f5df0c28193792a551f33de2b2292458183 Mon Sep 17 00:00:00 2001 From: Zachary Carter <zack.carter@gmail.com> Date: Tue, 19 Jun 2012 15:51:41 -0700 Subject: [PATCH] Add a flag to heartbeat to "deep check" dependent processes - issue #1767 --- bin/router | 6 ++-- lib/heartbeat.js | 73 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/bin/router b/bin/router index 56db15569..dc409f512 100755 --- a/bin/router +++ b/bin/router @@ -49,7 +49,10 @@ if (!config.get('browserid_url')) { // #1 - Setup health check / heartbeat middleware. // This is in front of logging on purpose. see issue #537 -heartbeat.setup(app); +var browserid_url = urlparse(config.get('browserid_url')).validate().normalize().originOnly(); +heartbeat.setup(app, { + dependencies: [browserid_url] +}); // #2 - logging! all requests other than __heartbeat__ are logged app.use(express.logger({ @@ -119,7 +122,6 @@ wsapi.setup({ }, app); // Forward all leftover requests to browserid -var browserid_url = urlparse(config.get('browserid_url')).validate().normalize().originOnly(); app.use(function(req, res, next) { forward( browserid_url+req.url, req, res, diff --git a/lib/heartbeat.js b/lib/heartbeat.js index 666e77767..885a435bf 100644 --- a/lib/heartbeat.js +++ b/lib/heartbeat.js @@ -4,26 +4,76 @@ const urlparse = require('urlparse'), -logger = require('./logging.js').logger; +logger = require('./logging.js').logger, +url = require('url'); // the path that heartbeats live at exports.path = '/__heartbeat__'; // a helper function to set up a heartbeat check -exports.setup = function(app, cb) { +exports.setup = function(app, options, cb) { + var dependencies = []; + + if (typeof options == 'function') { + cb = options; + } else if (options) { + dependencies = options.dependencies; + } + var count = dependencies.length; + app.use(function(req, res, next) { if (req.method === 'GET' && req.path === exports.path) { - function ok(yeah) { + var checked = 0; + var query = url.parse(req.url, true).query; + var deep = typeof query.deep != 'undefined'; + var notOk = []; + + // callback for checking a dependency + function checkCB (num) { + return function (isOk) { + checked++; + if (!isOk) { + notOk.push(dependencies[num]); + } + + // if all dependencies have been checked + if (checked == count) { + if (notOk.length === 0) { + try { + if (cb) cb(ok); + else ok(true); + } catch(e) { + logger.error("Exception caught in heartbeat handler: " + e.toString()); + ok(false, e); + } + } else { + logger.error("Not all dependencies available"); + ok(false, notOk.join(': failed\n') + ': failed'); + } + } + }; + } + + function ok(yeah, msg) { res.writeHead(yeah ? 200 : 500); - res.write(yeah ? 'ok' : 'not ok'); + res.write(yeah ? 'ok' : 'bad'); + if (msg) res.write(msg); res.end(); } - try { - if (cb) cb(ok); - else ok(true); - } catch(e) { - logger.error("Exception caught in heartbeat handler: " + e.toString()); - ok(false); + + // check all dependencies if deep + if (deep) { + for (var i = 0; i < count; i++) { + check(dependencies[i] + exports.path, checkCB(i)); + } + } else { + try { + if (cb) cb(ok); + else ok(true); + } catch(e) { + logger.error("Exception caught in heartbeat handler: " + e.toString()); + ok(false); + } } } else { return next(); @@ -31,8 +81,9 @@ exports.setup = function(app, cb) { }); }; + // a function to check the heartbeat of a remote server -exports.check = function(url, cb) { +var check = exports.check = function(url, cb) { if (typeof url === 'string') url = urlparse(url).normalize().validate(); else if (typeof url !== 'object') throw "url string or object required as argumnet to heartbeat.check"; if (!url.port) url.port = (url.scheme === 'http') ? 80 : 443; -- GitLab