Merge branch 'bg-lock-compiles'
This commit is contained in:
@@ -15,8 +15,11 @@ module.exports = CompileController =
|
||||
request.user_id = req.params.user_id if req.params.user_id?
|
||||
ProjectPersistenceManager.markProjectAsJustAccessed request.project_id, (error) ->
|
||||
return next(error) if error?
|
||||
CompileManager.doCompile request, (error, outputFiles = []) ->
|
||||
if error instanceof Errors.FilesOutOfSyncError
|
||||
CompileManager.doCompileWithLock request, (error, outputFiles = []) ->
|
||||
if error instanceof Errors.AlreadyCompilingError
|
||||
code = 423 # Http 423 Locked
|
||||
status = "compile-in-progress"
|
||||
else if error instanceof Errors.FilesOutOfSyncError
|
||||
code = 409 # Http 409 Conflict
|
||||
status = "retry"
|
||||
else if error?.terminated
|
||||
|
||||
@@ -9,6 +9,7 @@ Metrics = require "./Metrics"
|
||||
child_process = require "child_process"
|
||||
DraftModeManager = require "./DraftModeManager"
|
||||
TikzManager = require "./TikzManager"
|
||||
LockManager = require "./LockManager"
|
||||
fs = require("fs")
|
||||
fse = require "fs-extra"
|
||||
os = require("os")
|
||||
@@ -26,6 +27,18 @@ getCompileDir = (project_id, user_id) ->
|
||||
Path.join(Settings.path.compilesDir, getCompileName(project_id, user_id))
|
||||
|
||||
module.exports = CompileManager =
|
||||
|
||||
doCompileWithLock: (request, callback = (error, outputFiles) ->) ->
|
||||
compileDir = getCompileDir(request.project_id, request.user_id)
|
||||
lockFile = Path.join(compileDir, ".project-lock")
|
||||
# use a .project-lock file in the compile directory to prevent
|
||||
# simultaneous compiles
|
||||
fse.ensureDir compileDir, (error) ->
|
||||
return callback(error) if error?
|
||||
LockManager.runWithLock lockFile, (releaseLock) ->
|
||||
CompileManager.doCompile(request, releaseLock)
|
||||
, callback
|
||||
|
||||
doCompile: (request, callback = (error, outputFiles) ->) ->
|
||||
compileDir = getCompileDir(request.project_id, request.user_id)
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ FilesOutOfSyncError = (message) ->
|
||||
return error
|
||||
FilesOutOfSyncError.prototype.__proto__ = Error.prototype
|
||||
|
||||
AlreadyCompilingError = (message) ->
|
||||
error = new Error(message)
|
||||
error.name = "AlreadyCompilingError"
|
||||
error.__proto__ = AlreadyCompilingError.prototype
|
||||
return error
|
||||
AlreadyCompilingError.prototype.__proto__ = Error.prototype
|
||||
|
||||
module.exports = Errors =
|
||||
NotFoundError: NotFoundError
|
||||
FilesOutOfSyncError: FilesOutOfSyncError
|
||||
AlreadyCompilingError: AlreadyCompilingError
|
||||
|
||||
23
app/coffee/LockManager.coffee
Normal file
23
app/coffee/LockManager.coffee
Normal file
@@ -0,0 +1,23 @@
|
||||
Settings = require('settings-sharelatex')
|
||||
logger = require "logger-sharelatex"
|
||||
Lockfile = require('lockfile') # from https://github.com/npm/lockfile
|
||||
Errors = require "./Errors"
|
||||
|
||||
module.exports = LockManager =
|
||||
LOCK_TEST_INTERVAL: 1000 # 50ms between each test of the lock
|
||||
MAX_LOCK_WAIT_TIME: 15000 # 10s maximum time to spend trying to get the lock
|
||||
LOCK_STALE: 5*60*1000 # 5 mins time until lock auto expires
|
||||
|
||||
runWithLock: (path, runner = ((releaseLock = (error) ->) ->), callback = ((error) ->)) ->
|
||||
lockOpts =
|
||||
wait: @MAX_LOCK_WAIT_TIME
|
||||
pollPeriod: @LOCK_TEST_INTERVAL
|
||||
stale: @LOCK_STALE
|
||||
Lockfile.lock path, lockOpts, (error) ->
|
||||
return callback new Errors.AlreadyCompilingError("compile in progress") if error?.code is 'EEXIST'
|
||||
return callback(error) if error?
|
||||
runner (error1, args...) ->
|
||||
Lockfile.unlock path, (error2) ->
|
||||
error = error1 or error2
|
||||
return callback(error) if error?
|
||||
callback(null, args...)
|
||||
Reference in New Issue
Block a user