15

I find it extreemly cool to use standard syntax like

import scala.sys.process._
    val countLogger = ProcessLogger(line => {println ("out line: " + line)},
                                 line => {println ("err line: " + line)})

    val exitCode = ("cat prog.c" #&& "gcc prog.c -o prog -lm" 
            #&& "echo running, this may hang" #&& "prog.exe") ! countLogger

    println("exitCode = " + exitCode)

It however happens that last process hangs. Is it possible to kill it on timeout?

Val
  • 1
  • 8
  • 40
  • 64

1 Answers1

24

You can wrap your process in a Future(blocking(_)) and if it doesn't return after the time-out, you call process.destroy().

That's what I have done for my small Processor library, e.g. see here. Instead of using ! to eagerly wait for the exit-code, you use the run method. Here is an adaption from the README:

import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.sys.process._

val p = "sleep 100".run()               // start asynchronously
val f = Future(blocking(p.exitValue())) // wrap in Future
val res = try {
  Await.result(f, duration.Duration(2, "sec"))
} catch {
  case _: TimeoutException => 
    println("TIMEOUT!")
    p.destroy()
    p.exitValue()
}
0__
  • 66,707
  • 21
  • 171
  • 266
  • I have edited your question to demonstrate how to use this techinique with multiple commands and output capture. It works. Nevertheless, this article says that using `Await.result` is worse than not using Futures at all. Can you say why this does not apply in our case? – Val Mar 16 '15 at 08:32
  • 2
    Well, the idea of futures is to let them do whatever they do asynchronously. So `Await` is kind of counter-intuitive. But if you want a time-out, that's the way to solve it, while still playing nicely with futures. In the real scenario you wouldn't block your main thread with `Await` but wrap that in a `Future` as well and that would be the actual future result to use in your main logic. Instead of returning the `exitValue` in the time-out case, you could re-throw the time-out exception. For example, in my Processor library, calling `abort` will complete the future with `Processor.Aborted`. – 0__ Mar 16 '15 at 09:43
  • Hey, this solution works fine but it also throws `java.lang.ThreadDeath` in the caller thread when calling `destroy()`. Isn't there any issue with that? Why does it try to kill the caller thread and not simply the spawned process? – Sebastien Lorber Nov 05 '16 at 15:21