在akka actor中运行外部命令。抓住异常

时间:2016-10-07 12:19:46

标签: scala exception process actor

我不知道如何以简单的方式重现我的问题。

我有一个演员,通过' sys.process'执行外部命令。封装

object FileHelper {

  def downloadFile(url: String, filename: String): Either[String, Unit] = {
    println(s"MyThread: ${Thread.currentThread().getName}")
    util.Try {
      import scala.language.postfixOps
      new URL(url) #> new File(filename) !
    } match {
      case util.Failure(err) => Left(s"Download error: $err")
      case util.Success(code) => if (code != 0) Left("Can't download file") else Right({})
    }
  }

}

所以当我在演员中调用dowloadFile时,Try语句不起作用!

router MyThread: app-akka.actor.default-dispatcher-3
router[ERROR] Exception in thread "Thread-10" java.io.FileNotFoundException: /home/alex/dumpss/456.tar.bz2 (No such file or directory)
router[ERROR]   at java.io.FileOutputStream.open0(Native Method)
router[ERROR]   at java.io.FileOutputStream.open(FileOutputStream.java:270)
router[ERROR]   at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
router[ERROR]   at scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3.apply(ProcessBuilderImpl.scala:33)
router[ERROR]   at scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3.apply(ProcessBuilderImpl.scala:33)
router[ERROR]   at scala.sys.process.ProcessBuilderImpl$OStreamBuilder$$anonfun$$lessinit$greater$4.apply(ProcessBuilderImpl.scala:38)
router[ERROR]   at scala.sys.process.ProcessBuilderImpl$OStreamBuilder$$anonfun$$lessinit$greater$4.apply(ProcessBuilderImpl.scala:38)
router[ERROR]   at scala.sys.process.ProcessBuilderImpl$ThreadBuilder$$anonfun$1.apply$mcV$sp(ProcessBuilderImpl.scala:58)
router[ERROR]   at scala.sys.process.ProcessImpl$Spawn$$anon$1.run(ProcessImpl.scala:23)

正如您所看到的,外部命令已在线程&#39; Thread-10&#39;中执行。但尝试在app-akka.actor.default-dispatcher-3&#39;中捕获异常。

1 个答案:

答案 0 :(得分:1)

使用scala进程api,url下载和文件重定向由线程而不是实际进程实现:https://github.com/scala/scala/blob/2.12.x/src/library/scala/sys/process/ProcessBuilderImpl.scala#L31-L64

所以,当这一行被执行时,

new URL(url) #> new File(filename) !

生成另外两个线程,一个用于下载url并将结果写入管道,另一个从管道读取并将其读取的任何内容写入文件。并且父线程(actor正在运行)等待它们的退出值,并相应地返回它们中的任何一个:https://github.com/scala/scala/blob/2.12.x/src/library/scala/sys/process/ProcessImpl.scala#L151

不幸的是,始终忽略文件重定向的退出值。因此,您无法通过检查管道的返回代码来判断操作是否成功。 https://github.com/scala/scala/blob/2.12.x/src/library/scala/sys/process/ProcessBuilderImpl.scala#L39

您可以在commons-io库的帮助下完成工作,而不是使用scala进程api:

Try {
  IOUtils.copy(url.openStream, new FileOutputStream(file))
} match {
  case Success(_) => ...
  case Failure(ex) => ...
}