CompileManager.coffee 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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("../../infrastructure/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. return callback null, "autocompile-backoff", []
  21. logger.log project_id: project_id, user_id: user_id, "compiling project"
  22. CompileManager._checkIfRecentlyCompiled project_id, user_id, (error, recentlyCompiled) ->
  23. return callback(error) if error?
  24. if recentlyCompiled
  25. return callback new Error("project was recently compiled so not continuing")
  26. CompileManager._ensureRootDocumentIsSet project_id, (error) ->
  27. return callback(error) if error?
  28. DocumentUpdaterHandler.flushProjectToMongo project_id, (error) ->
  29. return callback(error) if error?
  30. ClsiManager.sendRequest project_id, (error, status, outputFiles) ->
  31. return callback(error) if error?
  32. logger.log files: outputFiles, "output files"
  33. if status == "failure"
  34. # Sometimes compiles fail because the project gets in a broken
  35. # state in LaTeX. So always clear cache on a failure.
  36. # Can do this in the background.
  37. ClsiManager.deleteAuxFiles project_id
  38. callback(null, status, outputFiles)
  39. getLogLines: (project_id, callback)->
  40. Metrics.inc "editor.raw-logs"
  41. ClsiManager.getLogLines project_id, (error, logLines)->
  42. return callback(error) if error?
  43. callback null, logLines
  44. COMPILE_DELAY: 1 # seconds
  45. _checkIfRecentlyCompiled: (project_id, user_id, callback = (error, recentlyCompiled) ->) ->
  46. key = "compile:#{project_id}:#{user_id}"
  47. rclient.set key, true, "EX", @COMPILE_DELAY, "NX", (error, ok) ->
  48. return callback(error) if error?
  49. if ok == "OK"
  50. return callback null, false
  51. else
  52. return callback null, true
  53. _checkIfAutoCompileLimitHasBeenHit: (isAutoCompile, callback = (err, canCompile)->)->
  54. if !isAutoCompile
  55. return callback(null, true)
  56. opts =
  57. endpointName:"auto_compile"
  58. timeInterval:15
  59. subjectName:"everyone"
  60. throttle: 10
  61. rateLimiter.addCount opts, (err, canCompile)->
  62. if err?
  63. canCompile = false
  64. logger.log canCompile:canCompile, opts:opts, "checking if auto compile limit has been hit"
  65. callback err, canCompile
  66. _ensureRootDocumentIsSet: (project_id, callback = (error) ->) ->
  67. Project.findById project_id, 'rootDoc_id', (error, project)=>
  68. return callback(error) if error?
  69. if !project?
  70. return callback new Error("project not found")
  71. if project.rootDoc_id?
  72. callback()
  73. else
  74. ProjectRootDocManager.setRootDocAutomatically project_id, callback