A number of our systems running Express/Node.js have implemented a /healthcheck endpoint that our load balancers and other monitoring systems can watch to detect when one of our applications is in trouble. Basically the endpoint checks connections to all downstream dependencies the app has, including MongoDB.
This issue is that when the /healthcheck endpoint tries to run its test transaction and it fails, there's no obvious way to catch the error in the endpoint so that I can have it report that the MongoDB dependency has an issue. Instead the server throws a 500 error for the /healthcheck request (while still detectable as an issue, is not as helpful).
This code shows basically what we're doing. It's not complete and runnable, but Express users with Mongoose experience should recognize it easily.
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const HealthcheckSchema = new Schema({
widget: {
type: String,
required: true,
unique: false,
},
createdAt: Date,
})
const HealthCheck = mongoose.model('Healthcheck', HealthcheckSchema, 'healthcheck')
const mongoCheck = () => Healthcheck.remove({}).exec()
.then(() => Healthcheck.create({widget: 'xyzpdq'}))
.then((results) => Healthcheck.findOne({widget: results.widget}).exec())
.then(() => true)
.catch(() => false)
const healthCheckEndpoint = (req, res) => {
let status = {}
Promise.all([mongoCheck()]) // normally there are other checks as well
.then(function (values) {
status.mongoUp = values[0]
return res.status(200).json(status) // always return 200; the payload gives the health status, not the HTTP status code
})
}
app.get('/healthcheck', healthCheckEndpoint)
In the main setup for the application, not specific to the healthcheck, we use mongoose.connect() with a callback. We have event handlers for various states like disconnected and error and such, and those events catch, but that doesn't help get the proper status in the /healthcheck endpoint.
I imagine I could use those event handlers to set state that the /healthcheck could pick up upon and return that, but I'd really prefer to make an actual query and use its success/failure as the result.