| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- const Metrics = require('metrics-sharelatex')
- const logger = require('logger-sharelatex')
- // TODO: domain has been deprecated for some time - do we need it and is there a better way?
- // eslint-disable-next-line node/no-deprecated-api
- const domain = require('domain')
- const TWO_MINUTES = 120 * 1000
- class ExceptionHandler {
- constructor() {
- this._appIsOk = true
- }
- beginShutdown() {
- if (this._appIsOk) {
- this._appIsOk = false
- // hard-terminate this process if graceful shutdown fails
- const killTimer = setTimeout(() => process.exit(1), TWO_MINUTES)
- if (typeof killTimer.unref === 'function') {
- killTimer.unref()
- } // prevent timer from keeping process alive
- this.server.close(function() {
- logger.log('closed all connections')
- Metrics.close()
- if (typeof process.disconnect === 'function') {
- process.disconnect()
- }
- })
- logger.log('server will stop accepting connections')
- }
- }
- addMiddleware(app) {
- app.use(this.middleware.bind(this))
- }
- appIsOk() {
- return this._appIsOk
- }
- setNotOk() {
- this._appIsOk = false
- }
- middleware(req, res, next) {
- const rescueLogger = require('logger-sharelatex')
- const requestDomain = domain.create()
- requestDomain.add(req)
- requestDomain.add(res)
- requestDomain.on('error', err => {
- try {
- // request a shutdown to prevent memory leaks
- this.beginShutdown()
- if (!res.headerSent) {
- res.send('uncaught exception').status(500)
- }
- req = {
- body: req.body,
- headers: req.headers,
- url: req.url,
- key: req.key,
- statusCode: req.statusCode
- }
- err = {
- message: err.message,
- stack: err.stack,
- name: err.name,
- type: err.type,
- arguments: err.arguments
- }
- rescueLogger.err(
- { err, req, res },
- 'uncaught exception thrown on request'
- )
- } catch (exception) {
- rescueLogger.err(
- { err: exception },
- 'exception in request domain handler'
- )
- }
- })
- if (!this._appIsOk) {
- // when shutting down, close any HTTP keep-alive connections
- res.set('Connection', 'close')
- }
- requestDomain.run(next)
- }
- }
- module.exports = ExceptionHandler
|