add support for stopping compile
This commit is contained in:
@@ -56,6 +56,7 @@ app.param 'build_id', (req, res, next, build_id) ->
|
|||||||
|
|
||||||
|
|
||||||
app.post "/project/:project_id/compile", bodyParser.json(limit: "5mb"), CompileController.compile
|
app.post "/project/:project_id/compile", bodyParser.json(limit: "5mb"), CompileController.compile
|
||||||
|
app.post "/project/:project_id/compile/stop", CompileController.stopCompile
|
||||||
app.delete "/project/:project_id", CompileController.clearCache
|
app.delete "/project/:project_id", CompileController.clearCache
|
||||||
|
|
||||||
app.get "/project/:project_id/sync/code", CompileController.syncFromCode
|
app.get "/project/:project_id/sync/code", CompileController.syncFromCode
|
||||||
@@ -65,6 +66,7 @@ app.get "/project/:project_id/status", CompileController.status
|
|||||||
|
|
||||||
# Per-user containers
|
# Per-user containers
|
||||||
app.post "/project/:project_id/user/:user_id/compile", bodyParser.json(limit: "5mb"), CompileController.compile
|
app.post "/project/:project_id/user/:user_id/compile", bodyParser.json(limit: "5mb"), CompileController.compile
|
||||||
|
app.post "/project/:project_id/user/:user_id/compile/stop", CompileController.stopCompile
|
||||||
app.delete "/project/:project_id/user/:user_id", CompileController.clearCache
|
app.delete "/project/:project_id/user/:user_id", CompileController.clearCache
|
||||||
|
|
||||||
app.get "/project/:project_id/user/:user_id/sync/code", CompileController.syncFromCode
|
app.get "/project/:project_id/user/:user_id/sync/code", CompileController.syncFromCode
|
||||||
|
|||||||
@@ -9,9 +9,27 @@ module.exports = CommandRunner =
|
|||||||
logger.log project_id: project_id, command: command, directory: directory, "running command"
|
logger.log project_id: project_id, command: command, directory: directory, "running command"
|
||||||
logger.warn "timeouts and sandboxing are not enabled with CommandRunner"
|
logger.warn "timeouts and sandboxing are not enabled with CommandRunner"
|
||||||
|
|
||||||
proc = spawn command[0], command.slice(1), stdio: "inherit", cwd: directory
|
# run command as detached process so it has its own process group (which can be killed if needed)
|
||||||
|
proc = spawn command[0], command.slice(1), stdio: "inherit", cwd: directory, detached: true
|
||||||
|
|
||||||
proc.on "error", (err)->
|
proc.on "error", (err)->
|
||||||
logger.err err:err, project_id:project_id, command: command, directory: directory, "error running command"
|
logger.err err:err, project_id:project_id, command: command, directory: directory, "error running command"
|
||||||
callback(err)
|
callback(err)
|
||||||
proc.on "close", () ->
|
|
||||||
|
proc.on "close", (code, signal) ->
|
||||||
|
logger.info code:code, signal:signal, project_id:project_id, "command exited"
|
||||||
|
if signal is 'SIGTERM' # signal from kill method below
|
||||||
|
err = new Error("terminated")
|
||||||
|
err.terminated = true
|
||||||
|
return callback(err)
|
||||||
|
else
|
||||||
|
callback()
|
||||||
|
|
||||||
|
return proc.pid # return process id to allow job to be killed if necessary
|
||||||
|
|
||||||
|
kill: (pid, callback = (error) ->) ->
|
||||||
|
try
|
||||||
|
process.kill -pid # kill all processes in group
|
||||||
|
catch err
|
||||||
|
return callback(err)
|
||||||
callback()
|
callback()
|
||||||
@@ -15,7 +15,9 @@ module.exports = CompileController =
|
|||||||
ProjectPersistenceManager.markProjectAsJustAccessed request.project_id, (error) ->
|
ProjectPersistenceManager.markProjectAsJustAccessed request.project_id, (error) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
CompileManager.doCompile request, (error, outputFiles = []) ->
|
CompileManager.doCompile request, (error, outputFiles = []) ->
|
||||||
if error?
|
if error?.terminated
|
||||||
|
status = "terminated"
|
||||||
|
else if error?
|
||||||
logger.error err: error, project_id: request.project_id, "error running compile"
|
logger.error err: error, project_id: request.project_id, "error running compile"
|
||||||
if error.timedout
|
if error.timedout
|
||||||
status = "timedout"
|
status = "timedout"
|
||||||
@@ -44,6 +46,12 @@ module.exports = CompileController =
|
|||||||
build: file.build
|
build: file.build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopCompile: (req, res, next) ->
|
||||||
|
{project_id, user_id, session_id} = req.params
|
||||||
|
CompileManager.stopCompile project_id, user_id, (error) ->
|
||||||
|
return next(error) if error?
|
||||||
|
res.sendStatus(204)
|
||||||
|
|
||||||
clearCache: (req, res, next = (error) ->) ->
|
clearCache: (req, res, next = (error) ->) ->
|
||||||
ProjectPersistenceManager.clearProject req.params.project_id, req.params.user_id, (error) ->
|
ProjectPersistenceManager.clearProject req.params.project_id, req.params.user_id, (error) ->
|
||||||
return next(error) if error?
|
return next(error) if error?
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ module.exports = CompileManager =
|
|||||||
timeout: request.timeout
|
timeout: request.timeout
|
||||||
image: request.imageName
|
image: request.imageName
|
||||||
}, (error, output, stats, timings) ->
|
}, (error, output, stats, timings) ->
|
||||||
|
# compile was killed by user
|
||||||
|
if error?.terminated
|
||||||
|
OutputFileFinder.findOutputFiles request.resources, compileDir, (err, outputFiles) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
callback(error, outputFiles) # return output files so user can check logs
|
||||||
|
return
|
||||||
|
# compile completed normally
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
Metrics.inc("compiles-succeeded")
|
Metrics.inc("compiles-succeeded")
|
||||||
for metric_key, metric_value of stats or {}
|
for metric_key, metric_value of stats or {}
|
||||||
@@ -78,6 +85,10 @@ module.exports = CompileManager =
|
|||||||
OutputCacheManager.saveOutputFiles outputFiles, compileDir, (error, newOutputFiles) ->
|
OutputCacheManager.saveOutputFiles outputFiles, compileDir, (error, newOutputFiles) ->
|
||||||
callback null, newOutputFiles
|
callback null, newOutputFiles
|
||||||
|
|
||||||
|
stopCompile: (project_id, user_id, callback = (error) ->) ->
|
||||||
|
compileName = getCompileName(project_id, user_id)
|
||||||
|
LatexRunner.killLatex compileName, callback
|
||||||
|
|
||||||
clearProject: (project_id, user_id, _callback = (error) ->) ->
|
clearProject: (project_id, user_id, _callback = (error) ->) ->
|
||||||
callback = (error) ->
|
callback = (error) ->
|
||||||
_callback(error)
|
_callback(error)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ logger = require "logger-sharelatex"
|
|||||||
Metrics = require "./Metrics"
|
Metrics = require "./Metrics"
|
||||||
CommandRunner = require(Settings.clsi?.commandRunner or "./CommandRunner")
|
CommandRunner = require(Settings.clsi?.commandRunner or "./CommandRunner")
|
||||||
|
|
||||||
|
ProcessTable = {} # table of currently running jobs (pids or docker container names)
|
||||||
|
|
||||||
module.exports = LatexRunner =
|
module.exports = LatexRunner =
|
||||||
runLatex: (project_id, options, callback = (error) ->) ->
|
runLatex: (project_id, options, callback = (error) ->) ->
|
||||||
{directory, mainFile, compiler, timeout, image} = options
|
{directory, mainFile, compiler, timeout, image} = options
|
||||||
@@ -30,7 +32,10 @@ module.exports = LatexRunner =
|
|||||||
if Settings.clsi?.strace
|
if Settings.clsi?.strace
|
||||||
command = ["strace", "-o", "strace", "-ff"].concat(command)
|
command = ["strace", "-o", "strace", "-ff"].concat(command)
|
||||||
|
|
||||||
CommandRunner.run project_id, command, directory, image, timeout, (error, output) ->
|
id = "#{project_id}" # record running project under this id
|
||||||
|
|
||||||
|
ProcessTable[id] = CommandRunner.run project_id, command, directory, image, timeout, (error, output) ->
|
||||||
|
delete ProcessTable[id]
|
||||||
return callback(error) if error?
|
return callback(error) if error?
|
||||||
runs = output?.stderr?.match(/^Run number \d+ of .*latex/mg)?.length or 0
|
runs = output?.stderr?.match(/^Run number \d+ of .*latex/mg)?.length or 0
|
||||||
failed = if output?.stdout?.match(/^Latexmk: Errors/m)? then 1 else 0
|
failed = if output?.stdout?.match(/^Latexmk: Errors/m)? then 1 else 0
|
||||||
@@ -49,6 +54,14 @@ module.exports = LatexRunner =
|
|||||||
timings["sys-time"] = stderr?.match(/System time.*: (\d+.\d+)/m)?[1] or 0
|
timings["sys-time"] = stderr?.match(/System time.*: (\d+.\d+)/m)?[1] or 0
|
||||||
callback error, output, stats, timings
|
callback error, output, stats, timings
|
||||||
|
|
||||||
|
killLatex: (project_id, callback = (error) ->) ->
|
||||||
|
id = "#{project_id}"
|
||||||
|
logger.log {id:id}, "killing running compile"
|
||||||
|
if not ProcessTable[id]?
|
||||||
|
return callback new Error("no such project to kill")
|
||||||
|
else
|
||||||
|
CommandRunner.kill ProcessTable[id], callback
|
||||||
|
|
||||||
_latexmkBaseCommand: (Settings?.clsi?.latexmkCommandPrefix || []).concat(
|
_latexmkBaseCommand: (Settings?.clsi?.latexmkCommandPrefix || []).concat(
|
||||||
["latexmk", "-cd", "-f", "-jobname=output", "-auxdir=$COMPILE_DIR", "-outdir=$COMPILE_DIR"]
|
["latexmk", "-cd", "-f", "-jobname=output", "-auxdir=$COMPILE_DIR", "-outdir=$COMPILE_DIR"]
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user