Scala - getting a callback when an external process exits

前端 未结 3 935
慢半拍i
慢半拍i 2021-01-02 05:08

I\'m looking to replace a lot of my perl with scala. One of the things I tend to do a lot is call binaries (usually compiled C++, but could be java, other perl scripts, q sc

相关标签:
3条回答
  • Have you considered spawning a new thread which will then call the blocking method process.exitValue()? You can then call your callback.

    0 讨论(0)
  • 2021-01-02 05:39

    updated version using spawn to create a new thread that blocks and waits for the exit code

    class Exe(command:String, out:String=>Unit, err:String=>Unit, onExit:Int=>Unit) {
    
        import scala.sys.process._
        import scala.io._
        import java.io._
        import scala.concurrent._
        import scala.concurrent.ops.spawn
    
        val inputStream = new SyncVar[OutputStream];
    
        val process = Process(command).run(
            new ProcessIO(
                stdin => inputStream.put(stdin),
                stdout => Source.fromInputStream(stdout).getLines.foreach(out),
                stderr => Source.fromInputStream(stderr).getLines.foreach(err)));
    
        spawn { onExit(process.exitValue()) }
    
        def write(s:String):Unit = synchronized {
            inputStream.get.write((s + "\n").getBytes)
        }
    
        def close():Unit = {
            inputStream.get.close
        }
    }
    

    can use like this

    import java.util.concurrent.CountDownLatch
    
    val latch = new CountDownLatch(1)
    
    val exe = new Exe("tr [a-z] [A-Z]",
            out => println("o: " + out), 
            err => println("e: " + err), 
            code=> {println(code) ; latch.countDown() })
    exe.write("lower") 
    exe.close()
    
    latch.await
    

    prints

    o: LOWER
    0
    

    thanks everyone!

    0 讨论(0)
  • 2021-01-02 05:41

    You can wait for the end of a process calling exitValue. You might do that in a separate thread, in which the callback will happen. Maybe class Process could be pimped thus:

    import scala.concurrent.ops.spawn
    implicit def ProcessWithCallback(p: Process) {
      def whenTerminatedDo(callback: Int => Unit) = spawn{
        val exitValue = p.exitValue; callback(p)
      }
    }
    

    You could then use that in Exe as you like.

    The Process class given by the JVM and wrapped by scala.sys.Process is really rather feable, it will be hard not to block a thread

    0 讨论(0)
提交回复
热议问题