Merge pull request #240 from CartoDB/health-check
Add healthcheck endpoint
This commit is contained in:
commit
597f8a7bab
5
NEWS.md
5
NEWS.md
@ -1,6 +1,8 @@
|
||||
1.21.3 -- 2014-mm-dd
|
||||
1.22.0 -- 2014-mm-dd
|
||||
--------------------
|
||||
|
||||
New features:
|
||||
- Health check endpoint
|
||||
|
||||
1.21.2 -- 2014-12-15
|
||||
--------------------
|
||||
@ -19,6 +21,7 @@ Bugfixes:
|
||||
- Closes fd for log files on `kill -HUP` (#230)
|
||||
|
||||
|
||||
|
||||
1.21.0 -- 2014-10-24
|
||||
--------------------
|
||||
|
||||
|
@ -151,6 +151,14 @@ var config = {
|
||||
// X-Tiler-Profile header containing elapsed timing for various
|
||||
// steps taken for producing the response.
|
||||
,useProfiler:true
|
||||
// Settings for the health check available at /health
|
||||
,health: {
|
||||
enabled: false,
|
||||
username: 'localhost',
|
||||
z: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@ -160,6 +160,14 @@ var config = {
|
||||
handler: 'inline'
|
||||
}
|
||||
}
|
||||
// Settings for the health check available at /health
|
||||
,health: {
|
||||
enabled: true,
|
||||
username: 'localhost',
|
||||
z: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@ -160,6 +160,14 @@ var config = {
|
||||
handler: 'inline'
|
||||
}
|
||||
}
|
||||
// Settings for the health check available at /health
|
||||
,health: {
|
||||
enabled: false,
|
||||
username: 'localhost',
|
||||
z: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@ -147,6 +147,14 @@ var config = {
|
||||
// X-Tiler-Profile header containing elapsed timing for various
|
||||
// steps taken for producing the response.
|
||||
,useProfiler:true
|
||||
// Settings for the health check available at /health
|
||||
,health: {
|
||||
enabled: false,
|
||||
username: 'localhost',
|
||||
z: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
@ -5,6 +5,7 @@ var _ = require('underscore')
|
||||
, TemplateMaps = require('./template_maps.js')
|
||||
, Cache = require('./cache_validator')
|
||||
, os = require('os')
|
||||
, HealthCheck = require('./monitoring/health_check')
|
||||
;
|
||||
|
||||
if ( ! process.env['PGAPPNAME'] )
|
||||
@ -665,6 +666,31 @@ var CartodbWindshaft = function(serverOptions) {
|
||||
|
||||
// ---- Template maps interface ends @}
|
||||
|
||||
var healthCheck = new HealthCheck(cartoData, Windshaft.tilelive);
|
||||
ws.get('/health', function(req, res) {
|
||||
var healthConfig = global.environment.health || {};
|
||||
|
||||
if (!!healthConfig.enabled) {
|
||||
var startTime = Date.now();
|
||||
healthCheck.check(healthConfig, function(err, result) {
|
||||
var ok = !err;
|
||||
var response = {
|
||||
enabled: true,
|
||||
ok: ok,
|
||||
elapsed: Date.now() - startTime,
|
||||
result: result
|
||||
};
|
||||
if (err) {
|
||||
response.err = err.message;
|
||||
}
|
||||
res.send(response, ok ? 200 : 503);
|
||||
|
||||
});
|
||||
} else {
|
||||
res.send({enabled: false, ok: true}, 200);
|
||||
}
|
||||
});
|
||||
|
||||
return ws;
|
||||
};
|
||||
|
||||
|
90
lib/cartodb/monitoring/health_check.js
Normal file
90
lib/cartodb/monitoring/health_check.js
Normal file
@ -0,0 +1,90 @@
|
||||
var _ = require('underscore'),
|
||||
dot = require('dot'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
Step = require('step');
|
||||
|
||||
function HealthCheck(metadataBackend, tilelive) {
|
||||
this.metadataBackend = metadataBackend;
|
||||
this.tilelive = tilelive;
|
||||
}
|
||||
|
||||
module.exports = HealthCheck;
|
||||
|
||||
|
||||
var mapnikOptions = {
|
||||
query: {
|
||||
metatile: 1,
|
||||
poolSize: 4,
|
||||
bufferSize: 64
|
||||
},
|
||||
protocol: 'mapnik:',
|
||||
slashes: true,
|
||||
xml: null
|
||||
};
|
||||
|
||||
var xmlTemplate = dot.template(fs.readFileSync(path.resolve(__dirname, 'map-config.xml'), 'utf-8'));
|
||||
|
||||
HealthCheck.prototype.check = function(config, callback) {
|
||||
|
||||
var self = this,
|
||||
startTime,
|
||||
result = {
|
||||
redis: {
|
||||
ok: false
|
||||
},
|
||||
mapnik: {
|
||||
ok: false
|
||||
},
|
||||
tile: {
|
||||
ok: false
|
||||
}
|
||||
};
|
||||
mapnikXmlParams = config;
|
||||
|
||||
Step(
|
||||
function getDBParams() {
|
||||
startTime = Date.now();
|
||||
self.metadataBackend.getAllUserDBParams(config.username, this);
|
||||
},
|
||||
function loadMapnik(err, dbParams) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
result.redis = {
|
||||
ok: !err,
|
||||
elapsed: Date.now() - startTime,
|
||||
size: Object.keys(dbParams).length
|
||||
};
|
||||
mapnikOptions.xml = xmlTemplate(mapnikXmlParams);
|
||||
|
||||
startTime = Date.now();
|
||||
self.tilelive.load(mapnikOptions, this);
|
||||
},
|
||||
function getTile(err, source) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
result.mapnik = {
|
||||
ok: !err,
|
||||
elapsed: Date.now() - startTime
|
||||
};
|
||||
|
||||
startTime = Date.now();
|
||||
source.getTile(config.z, config.x, config.y, this);
|
||||
},
|
||||
function handleTile(err, tile) {
|
||||
result.tile = {
|
||||
ok: !err
|
||||
};
|
||||
|
||||
if (tile) {
|
||||
result.tile.elapsed = Date.now() - startTime;
|
||||
result.tile.size = tile.length;
|
||||
}
|
||||
|
||||
callback(err, result);
|
||||
}
|
||||
);
|
||||
};
|
4
lib/cartodb/monitoring/map-config.xml
Normal file
4
lib/cartodb/monitoring/map-config.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<Map
|
||||
background-color="#c33"
|
||||
srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
|
||||
</Map>
|
23
npm-shrinkwrap.json
generated
23
npm-shrinkwrap.json
generated
@ -96,7 +96,7 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@2"
|
||||
"from": "inherits@~2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,6 +149,7 @@
|
||||
"rollbar": {
|
||||
"version": "0.3.13",
|
||||
"from": "rollbar@~0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/rollbar/-/rollbar-0.3.13.tgz",
|
||||
"dependencies": {
|
||||
"node-uuid": {
|
||||
"version": "1.4.2",
|
||||
@ -302,21 +303,23 @@
|
||||
"from": "tunnel-agent@~0.3.0"
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "0.10.0",
|
||||
"version": "0.10.1",
|
||||
"from": "http-signature@~0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
|
||||
"dependencies": {
|
||||
"assert-plus": {
|
||||
"version": "0.1.2",
|
||||
"from": "assert-plus@0.1.2"
|
||||
"version": "0.1.5",
|
||||
"from": "assert-plus@^0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz"
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.1.11",
|
||||
"from": "asn1@0.1.11"
|
||||
},
|
||||
"ctype": {
|
||||
"version": "0.5.2",
|
||||
"from": "ctype@0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.2.tgz"
|
||||
"version": "0.5.3",
|
||||
"from": "ctype@0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1615,9 +1618,9 @@
|
||||
"resolved": "https://registry.npmjs.org/connect/-/connect-1.9.2.tgz",
|
||||
"dependencies": {
|
||||
"formidable": {
|
||||
"version": "1.0.15",
|
||||
"version": "1.0.16",
|
||||
"from": "formidable@1.0.x",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.15.tgz"
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.16.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1681,7 +1684,7 @@
|
||||
},
|
||||
"sphericalmercator": {
|
||||
"version": "1.0.3",
|
||||
"from": "sphericalmercator@~1.0.1",
|
||||
"from": "sphericalmercator@~1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sphericalmercator/-/sphericalmercator-1.0.3.tgz"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "windshaft-cartodb",
|
||||
"version": "1.22.0",
|
||||
"version": "1.21.3",
|
||||
"description": "A map tile server for CartoDB",
|
||||
"keywords": [
|
||||
|
72
test/acceptance/health_check.js
Normal file
72
test/acceptance/health_check.js
Normal file
@ -0,0 +1,72 @@
|
||||
var helper = require(__dirname + '/../support/test_helper');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/cartodb_windshaft');
|
||||
var serverOptions = require(__dirname + '/../../lib/cartodb/server_options')();
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
suite('health checks', function () {
|
||||
|
||||
beforeEach(function (done) {
|
||||
global.environment.health = {
|
||||
enabled: true,
|
||||
username: 'localhost',
|
||||
z: 0,
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
done();
|
||||
});
|
||||
|
||||
var healthCheckRequest = {
|
||||
url: '/health',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
}
|
||||
};
|
||||
|
||||
test('returns 200 and ok=true with enabled configuration', function (done) {
|
||||
assert.response(server,
|
||||
healthCheckRequest,
|
||||
{
|
||||
status: 200
|
||||
},
|
||||
function (res, err) {
|
||||
console.log(res.body);
|
||||
assert.ok(!err);
|
||||
|
||||
var parsed = JSON.parse(res.body);
|
||||
|
||||
assert.ok(parsed.enabled);
|
||||
assert.ok(parsed.ok);
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('fails for invalid user because it is not in redis', function (done) {
|
||||
global.environment.health.username = 'invalid';
|
||||
|
||||
assert.response(server,
|
||||
healthCheckRequest,
|
||||
{
|
||||
status: 503
|
||||
},
|
||||
function (res, err) {
|
||||
assert.ok(!err);
|
||||
|
||||
var parsed = JSON.parse(res.body);
|
||||
|
||||
assert.equal(parsed.enabled, true);
|
||||
assert.equal(parsed.ok, false);
|
||||
|
||||
assert.equal(parsed.result.redis.ok, false);
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user