app.coffee 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. Metrics = require "metrics-sharelatex"
  2. Metrics.initialize("filestore")
  3. express = require('express')
  4. bodyParser = require "body-parser"
  5. logger = require('logger-sharelatex')
  6. logger.initialize("filestore")
  7. settings = require("settings-sharelatex")
  8. request = require("request")
  9. fileController = require("./app/js/FileController")
  10. bucketController = require("./app/js/BucketController")
  11. keyBuilder = require("./app/js/KeyBuilder")
  12. healthCheckController = require("./app/js/HealthCheckController")
  13. domain = require("domain")
  14. appIsOk = true
  15. app = express()
  16. if settings.sentry?.dsn?
  17. logger.initializeErrorReporting(settings.sentry.dsn)
  18. Metrics.open_sockets.monitor(logger)
  19. Metrics.event_loop?.monitor(logger)
  20. Metrics.memory.monitor(logger)
  21. app.use Metrics.http.monitor(logger)
  22. app.use (req, res, next)->
  23. Metrics.inc "http-request"
  24. next()
  25. app.use (req, res, next) ->
  26. requestDomain = domain.create()
  27. requestDomain.add req
  28. requestDomain.add res
  29. requestDomain.on "error", (err)->
  30. try
  31. # request a shutdown to prevent memory leaks
  32. beginShutdown()
  33. if !res.headerSent
  34. res.send(500, "uncaught exception")
  35. logger = require('logger-sharelatex')
  36. req =
  37. body:req.body
  38. headers:req.headers
  39. url:req.url
  40. key: req.key
  41. statusCode: req.statusCode
  42. err =
  43. message: err.message
  44. stack: err.stack
  45. name: err.name
  46. type: err.type
  47. arguments: err.arguments
  48. logger.err err:err, req:req, res:res, "uncaught exception thrown on request"
  49. catch exception
  50. logger.err err: exception, "exception in request domain handler"
  51. requestDomain.run next
  52. app.use (req, res, next) ->
  53. if not appIsOk
  54. # when shutting down, close any HTTP keep-alive connections
  55. res.set 'Connection', 'close'
  56. next()
  57. Metrics.injectMetricsRoute(app)
  58. app.get "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.getFile
  59. app.post "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.insertFile
  60. app.put "/project/:project_id/file/:file_id", keyBuilder.userFileKey, bodyParser.json(), fileController.copyFile
  61. app.del "/project/:project_id/file/:file_id", keyBuilder.userFileKey, fileController.deleteFile
  62. app.get "/template/:template_id/v/:version/:format", keyBuilder.templateFileKey, fileController.getFile
  63. app.get "/template/:template_id/v/:version/:format/:sub_type", keyBuilder.templateFileKey, fileController.getFile
  64. app.post "/template/:template_id/v/:version/:format", keyBuilder.templateFileKey, fileController.insertFile
  65. app.get "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.getFile
  66. app.post "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.insertFile
  67. app.put "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, bodyParser.json(), fileController.copyFile
  68. app.del "/project/:project_id/public/:public_file_id", keyBuilder.publicFileKey, fileController.deleteFile
  69. app.get "/project/:project_id/size", keyBuilder.publicProjectKey, fileController.directorySize
  70. app.get "/bucket/:bucket/key/*", bucketController.getFile
  71. app.get "/heapdump", (req, res)->
  72. require('heapdump').writeSnapshot '/tmp/' + Date.now() + '.filestore.heapsnapshot', (err, filename)->
  73. res.send filename
  74. app.post "/shutdown", (req, res)->
  75. appIsOk = false
  76. res.send()
  77. app.get '/status', (req, res)->
  78. if appIsOk
  79. res.send('filestore sharelatex up')
  80. else
  81. logger.log "app is not ok - shutting down"
  82. res.send("server is being shut down", 500)
  83. app.get "/health_check", healthCheckController.check
  84. app.get '*', (req, res)->
  85. res.send 404
  86. beginShutdown = () ->
  87. if appIsOk
  88. appIsOk = false
  89. # hard-terminate this process if graceful shutdown fails
  90. killTimer = setTimeout () ->
  91. process.exit 1
  92. , 120*1000
  93. killTimer.unref?() # prevent timer from keeping process alive
  94. app.close () ->
  95. logger.log "closed all connections"
  96. Metrics.close()
  97. process.disconnect?()
  98. logger.log "server will stop accepting connections"
  99. port = settings.internal.filestore.port or 3009
  100. host = "0.0.0.0"
  101. if !module.parent # Called directly
  102. app.listen port, host, (error) ->
  103. logger.info "Filestore starting up, listening on #{host}:#{port}"
  104. module.exports = app
  105. process.on 'SIGTERM', () ->
  106. logger.log("filestore got SIGTERM, shutting down gracefully")
  107. beginShutdown()
  108. if global.gc?
  109. gcTimer = setInterval () ->
  110. global.gc()
  111. logger.log process.memoryUsage(), "global.gc"
  112. , 3 * oneMinute = 60 * 1000
  113. gcTimer.unref()