diff --git a/index.js b/index.js index 272041c..4a9d20a 100644 --- a/index.js +++ b/index.js @@ -8,17 +8,11 @@ var debug = require('debug'); var error = debug('charon:error'); -var ClusterManager = require('cluster-man'); var server = require('./lib/server.js'); -var manager = new ClusterManager(function () { - server.start(function (err) { - if (err) { - error('Could not start server: ' + err); - process.kill(1); - } - }); +server.start(function (err) { + if (err) { + error('Could not start server: ' + err); + process.kill(1); + } }); - -// Start the cluster -manager.start(); diff --git a/lib/server.js b/lib/server.js index de746d4..3540a08 100644 --- a/lib/server.js +++ b/lib/server.js @@ -113,10 +113,10 @@ function socketError(err) { * @param {Error} err Unhandled error. */ function unhandledError(err) { - // TODO This should, potentially, kill the process. But we are gonna - // wait on the "nuclear" option until we have clustering. monitor.increment('error.unhandled'); + monitor.histogram('status', 0); unhandled(err.stack); + process.exit(1); } /** @@ -128,6 +128,7 @@ function start(cb) { // callback is executed after the server is listening (events, pfft). // TODO Rewrite simple UDP server to make it more robust (later). server.once('listening', function() { + monitor.histogram('status', 1); info('DNS Running on Port', process.env.PORT); cb(null); }); @@ -147,6 +148,7 @@ function stop(cb) { // callback is executed after the server is listening (events, pfft). // TODO Rewrite simple UDP server to make it more robust (later). server.once('close', function() { + monitor.histogram('status', 0); info('Server Shutdown'); cb(null); }); diff --git a/package.json b/package.json index a622bde..1b1aa70 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ }, "dependencies": { "callback-count": "^0.1.0", - "cluster-man": "^1.0.0", "debug": "^2.1.3", "dns-rcodes": "^1.0.0", "loadenv": "^1.0.3", diff --git a/test/functional/charon.js b/test/functional/charon.js index f94532d..3ba8562 100644 --- a/test/functional/charon.js +++ b/test/functional/charon.js @@ -11,6 +11,7 @@ var afterEach = lab.afterEach; var Code = require('code'); var expect = Code.expect; var sinon = require('sinon'); +var createCount = require('callback-count'); require('loadenv')('charon:env'); var server = require('../../lib/server'); @@ -90,6 +91,14 @@ describe('charon', function() { done(); }); }); + + it('should not crash after many repeated requests', function (done) { + var numRequests = 200; + var count = createCount(numRequests, done); + for (var i = 0; i < numRequests; i++) { + dnsRequest('example.runnableapp.com', count.next); + } + }) }); // end 'server (functional)' describe('monitoring', function () { diff --git a/test/unit/server.js b/test/unit/server.js index 4c0dd51..bee2f4d 100644 --- a/test/unit/server.js +++ b/test/unit/server.js @@ -101,49 +101,93 @@ describe('server', function() { }); // end 'api integration' describe('domains', function() { + var testError = new Error(); + beforeEach(function (done) { monitorStub.stubAll(); + var exitStub = sinon.stub(process, 'exit'); done(); }); afterEach(function (done) { monitorStub.restoreAll(); + process.exit.restore(); done(); }); it('should use domains to catch unhandled `start` exceptions', function (done) { expect(server.start.domain).to.exist(); sinon.stub(apiClient, 'login', function(cb) { - throw new Error(); + throw testError; cb(); }); - - server.start.domain.on('error', function errorListener() { + server.start.domain.on('error', function errorListener(err) { + expect(err).to.equal(testError); server.start.domain.removeListener('error', errorListener); - expect(monitor.increment.calledWith('error.unhandled')) - .to.be.true(); apiClient.login.restore(); done(); }); server.start(); }); - it ('should use domains to catch unhandled `stop` exceptions', function (done) { + it('should use domains to catch unhandled `stop` exceptions', function (done) { expect(server.stop.domain).to.exist(); sinon.stub(server.instance, 'close', function() { - throw new Error(); + throw testError; }); - - server.stop.domain.on('error', function errorListener() { - server.stop.domain.removeListener('error', errorListener); - expect(monitor.increment.calledWith('error.unhandled')) - .to.be.true(); + server.stop.domain.on('error', function errorListener(err) { + expect(err).to.equal(testError); server.instance.close.restore(); + server.stop.domain.removeListener('error', errorListener); done(); }); server.start(function() { server.stop(); }); }); + + describe('unhandledError', function() { + var domain = server.start.domain; + + beforeEach(function (done) { + sinon.stub(apiClient, 'login', function (cb) { + throw new Error(); + }); + done(); + }); + + afterEach(function (done) { + apiClient.login.restore(); + done(); + }); + + it('should exit the process', function (done) { + domain.on('error', function errorListener() { + expect(process.exit.calledOnce).to.be.true(); + expect(process.exit.calledWith(1)).to.be.true(); + domain.removeListener('error', errorListener); + done(); + }); + server.start(); + }); + + it('should monitor unhandled errors', function (done) { + domain.on('error', function errorListener() { + expect(monitor.increment.calledWith('error.unhandled')).to.be.true(); + domain.removeListener('error', errorListener); + done(); + }); + server.start(); + }); + + it('should set server status monitor to "down" (0)', function (done) { + domain.on('error', function errorListener() { + expect(monitor.histogram.calledWith('status', 0)).to.be.true(); + domain.removeListener('error', errorListener); + done(); + }); + server.start(); + }); + }); }); // end 'domains' }); // end 'server'