【问题标题】:Scala: how to manage fatal errors (like OOM) in FutureScala:如何在未来管理致命错误(如 OOM)
【发布时间】:2019-01-29 19:15:21
【问题描述】:

我们的分布式应用程序中有一些奇怪的行为。我们尚未找到原因,但我们认为这可能与 OutOfMemory 错误有关。

但是,对于致命错误,我们尝试遵循良好的编码实践,例如从不捕获所有可抛出的错误,以及最多非致命错误。但我意识到,对于 Future 中发生的致命错误,我有些不太明白,而且我们的代码几乎都被封装到 Future 中。

这是一个最小的例子:

val f = Future{ /* some code that makes an OOM error */ }
val result = Await.result(f, 1 minutes)

会发生什么

  • 运行未来代码的线程失败。 OOM 打印在 stderr 中。但是我们看不到它,因为应用程序部署在“某处”并且我们没有重定向标准错误
  • 但是,Future 并没有结束(它只捕获 NonFatal)。值得它不会释放资源。
  • 1 分钟后,我们得到与 OOM 无关的 TimeoutException。希望它释放资源。但是我们已经失去了时间,其他线程可能会受到影响。然后我们将其视为没有时间完成的未来。类似地,好像某些数据库访问没有及时响应,即我们通常会再试一次。

我在这里找到了一个很好的问题描述:https://github.com/scala/bug/issues/9554

我的问题:我们应该如何处理未来发生的致命错误?

  • 至少,整个应用程序应该会像在主线程中发生致命错误一样失败。也许有核心转储
  • 最好有适当的管理:记录异常,应用合适的重新执行模式,可能优雅地杀死其他正在运行的未来/线程,...

注意:这是与Exception causes Future to never complete 类似的问题,但答案是“这是有意的”而不是如何管理它

【问题讨论】:

  • 您考虑过这个解决方案吗? stackoverflow.com/a/3878199/227803
  • 不。实际上它在java中是同样的问题,这个解决方案可以在这里应用(这是我的问题的有效答案)。 OOM 是我最关心的问题,但你知道它是否可以应用于其他致命错误吗?
  • 试用 Scala 2.13.0-M5 发布后,我重新处理了致命错误,但我不知道它将如何影响您的特定代码。
  • 谢谢,等我出来看看

标签: scala future fatal-error


【解决方案1】:

我找到了一种方法,它需要将我们自己的 ExecutionContext 与包含我们自己的 UncaughtExceptionHandler 的 Executor 一起使用:

// UncaughtExceptionHandler that process Fatal error
val exceptionHandler = new Thread.UncaughtExceptionHandler {
  override def uncaughtException(t: Thread, err: Throwable): Unit =  err match {
    case NonFatal(_) =>
      // don't process NonFatal which should be managed by the processing code

    case t =>
      // process fatal error
      log.error("FATAL ERROR", t)
      System.exit(1)       
  }
}


// make the Execution context with our UncaughtExceptionHandler
//   here I chose a ForkJoinPool which is the type of EC.global
//   I hard-coded the thread number to 8. global use the number of available core
val fjp = new ForkJoinPool(8, ForkJoinPool.defaultForkJoinWorkerThreadFactory, exceptionHandler, false)
implicit val ec = ExecutionContext.fromExecutor(fjp)


// used implicitly in the future code
val f = Future{ /* some code that makes an OOM error */ }
val result = Await.result(f, 1 minutes)

【讨论】:

  • case t 可能会捕获到 mutch 异常。您不希望 Controlle 异常杀死您的 jvm。改用-XX:+ExitOnOutOfMemoryError
  • 是的,这里的错误管理很容易提出我的案例(并且符合我的第一个要求“至少,整个应用程序应该失败”)。这可能不是我们想要做的,或者不是所有的 fatalError。
猜你喜欢
  • 2015-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多