diff --git a/services/document-updater/app.coffee b/services/document-updater/app.coffee index 3717d2f272..b0813e47f9 100644 --- a/services/document-updater/app.coffee +++ b/services/document-updater/app.coffee @@ -9,6 +9,7 @@ DispatchManager = require('./app/js/DispatchManager') Keys = require('./app/js/RedisKeyBuilder') Errors = require "./app/js/Errors" HttpController = require "./app/js/HttpController" +MongoHealthCheck = require('./app/js/MongoHealthCheck') redis = require("redis-sharelatex") rclient = redis.createClient(Settings.redis.web) @@ -57,6 +58,12 @@ app.get '/status', (req, res)-> else res.send('document updater is alive') +app.get '/health_check/mongo', (req, res, next) -> + MongoHealthCheck.isAlive (error) -> + if error? + res.send 500, error.message + else + res.send 200 redisCheck = require("redis-sharelatex").activeHealthCheckRedis(Settings.redis.web) app.get "/health_check/redis", (req, res, next)-> diff --git a/services/document-updater/app/coffee/MongoHealthCheck.coffee b/services/document-updater/app/coffee/MongoHealthCheck.coffee new file mode 100644 index 0000000000..3872c051c4 --- /dev/null +++ b/services/document-updater/app/coffee/MongoHealthCheck.coffee @@ -0,0 +1,26 @@ +Settings = require "settings-sharelatex" +PersistenceManager = require "./PersistenceManager" + +module.exports = MongoHealthCheck = + isAlive: (_callback = (error) ->) -> + # We've seen very occasionally the doc-updater losing its connection to Mongo. + # E.g. https://sharelatex.hackpad.com/29th-Aug-2015-0650-0740-fHlw8RL8zuN + # It seems that the mongo callbacks never returned. + # Mongo is only called in the persistence manager, so we do a read-only + # test call, check that it's working, and returns in a reasonable time. + callback = (args...) -> + _callback(args...) + _callback = () -> + + doc_id = Settings.smokeTest?.doc_id + if !doc_id? + return callback(new Error("No test doc_id configured")) + + PersistenceManager.getDocVersionInMongo doc_id, (error, version) -> + return callback(error) if error? + callback(null) + + timeout = Settings.smokeTest?.timeout or 10000 + setTimeout () -> + callback(new Error("Mongo did not return in #{timeout}ms")) + , timeout \ No newline at end of file diff --git a/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee b/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee new file mode 100644 index 0000000000..b8da766a4c --- /dev/null +++ b/services/document-updater/test/unit/coffee/MongoHealthCheckTests/MongoHealthCheckTests.coffee @@ -0,0 +1,52 @@ +SandboxedModule = require('sandboxed-module') +sinon = require('sinon') +require('chai').should() +modulePath = require('path').join __dirname, '../../../../app/js/MongoHealthCheck' + +describe "MongoHealthCheck", -> + beforeEach -> + @MongoHealthCheck = SandboxedModule.require modulePath, requires: + "settings-sharelatex": @Settings = {} + "./PersistenceManager": @PersistenceManager = {} + @doc_id = "mock-doc-id" + @callback = sinon.stub() + + describe "isAlive", -> + describe "with no configured doc_id", -> + beforeEach -> + @MongoHealthCheck.isAlive @callback + + it "should call the call the callback with an error", -> + @callback.calledOnce.should.equal true + error = @callback.args[0][0] + error.message.should.equal "No test doc_id configured" + + describe "when mongo returns within the timeout", -> + beforeEach -> + @Settings.smokeTest = + doc_id: @doc_id + @PersistenceManager.getDocVersionInMongo = sinon.stub().callsArg(1) + @MongoHealthCheck.isAlive @callback + + it "should call PersistenceManager.getDocVersionInMongo", -> + @PersistenceManager.getDocVersionInMongo + .calledWith(@doc_id) + .should.equal true + + it "should call the call the callback without an error", -> + @callback.calledOnce.should.equal true + @callback.calledWith(null).should.equal true + + describe "when mongo does not return within the timeout", -> + beforeEach (done) -> + @Settings.smokeTest = + doc_id: @doc_id + timeout: 50 + @PersistenceManager.getDocVersionInMongo = (doc_id, callback) -> + setTimeout callback, 100 + @MongoHealthCheck.isAlive (@error) => + done() + + it "should call the call the callback with an error", -> + @error.message.should.equal "Mongo did not return in 50ms" + \ No newline at end of file