CompileManager.coffee 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. Settings = require('settings-sharelatex')
  2. redis = require('redis')
  3. rclient = redis.createClient(Settings.redis.web.port, Settings.redis.web.host)
  4. rclient.auth(Settings.redis.web.password)
  5. DocumentUpdaterHandler = require "../DocumentUpdater/DocumentUpdaterHandler"
  6. Project = require("../../models/Project").Project
  7. ProjectRootDocManager = require "../Project/ProjectRootDocManager"
  8. ClsiManager = require "./ClsiManager"
  9. Metrics = require('../../infrastructure/Metrics')
  10. logger = require("logger-sharelatex")
  11. RateLimiter = require("ratelimiter")
  12. module.exports = CompileManager =
  13. compile: (project_id, user_id, opt = {}, _callback = (error) ->) ->
  14. timer = new Metrics.Timer("editor.compile")
  15. callback = (args...) ->
  16. timer.done()
  17. _callback(args...)
  18. @_checkIfAutoCompileLimitHasBeenHit opt.isAutoCompile, (err, canCompile)->
  19. if !canCompile
  20. err = {rateLimitHit:true}
  21. return callback(err)
  22. logger.log project_id: project_id, user_id: user_id, "compiling project"
  23. CompileManager._checkIfRecentlyCompiled project_id, user_id, (error, recentlyCompiled) ->
  24. return callback(error) if error?
  25. if recentlyCompiled
  26. return callback new Error("project was recently compiled so not continuing")
  27. CompileManager._ensureRootDocumentIsSet project_id, (error) ->
  28. return callback(error) if error?
  29. DocumentUpdaterHandler.flushProjectToMongo project_id, (error) ->
  30. return callback(error) if error?
  31. ClsiManager.sendRequest project_id, (error, success, outputFiles) ->
  32. return callback(error) if error?
  33. logger.log files: outputFiles, "output files"
  34. callback(null, success, outputFiles)
  35. getLogLines: (project_id, callback)->
  36. Metrics.inc "editor.raw-logs"
  37. ClsiManager.getLogLines project_id, (error, logLines)->
  38. return callback(error) if error?
  39. callback null, logLines
  40. COMPILE_DELAY: 1 # seconds
  41. _checkIfRecentlyCompiled: (project_id, user_id, callback = (error, recentlyCompiled) ->) ->
  42. key = "compile:#{project_id}:#{user_id}"
  43. rclient.set key, true, "EX", @COMPILE_DELAY, "NX", (error, ok) ->
  44. return callback(error) if error?
  45. if ok == "OK"
  46. return callback null, false
  47. else
  48. return callback null, true
  49. _checkIfAutoCompileLimitHasBeenHit: (isAutoCompile, callback = (err, canCompile)->)->
  50. if !isAutoCompile
  51. return callback(null, true)
  52. key = "auto_compile_rate_limit"
  53. ten_seconds = (10 * 1000)
  54. limit = new RateLimiter(db:rclient, id:key, max:7, duration:ten_seconds)
  55. limit.get (err, limit)->
  56. Metrics.inc("compile.autocompile.rateLimitCheck")
  57. if limit.remaining > 0 and !err?
  58. canCompile = true
  59. else
  60. canCompile = false
  61. Metrics.inc("compile.autocompile.rateLimitHit")
  62. logger.log canCompile:canCompile, limit:limit, "checking if auto compile limit has been hit"
  63. callback err, canCompile
  64. _ensureRootDocumentIsSet: (project_id, callback = (error) ->) ->
  65. Project.findById project_id, 'rootDoc_id', (error, project)=>
  66. return callback(error) if error?
  67. if !project?
  68. return callback new Error("project not found")
  69. if project.rootDoc_id?
  70. callback()
  71. else
  72. ProjectRootDocManager.setRootDocAutomatically project_id, callback