在 Controller NonFatal 中捕获异常

Catching Exception in Controller NonFatal

假设我有以下控制器方法:

def getAllRules() = AuthAction("View" on "Rules").async {
   Metrics.measureTime("getAllRules", category = Category) {
     ruleService.getAllRules.map({
       case Nil => NoContent
       case rules => Ok(Json.toJson(rules.toViewRules))
     }).recover {
       case e: Exception => handlerError(s"Failure occurred on getAllRules, ex: ${e.getMessage}", "getAllRules")
     }
   }
}

handleError 是:

def handlerError(err: String, occurredOn: String): Result = {
    Metrics.errorsCounter(occurredOn).increment()
    logger.error(err)
    InternalServerError(Json.toJson(Json.obj("error" -> err)))
}

我明白捕获所有异常是错误的,我应该只捕获 NonFatal 个异常。

我想问:

  1. 什么是致命异常?怎么会发生? VirtualMachineError, InterruptedException, LinkageError, ControlThrowable
  2. 为什么捕获所有异常不好,而只捕获NonFatal
  3. Fatal 异常的情况下 - 它需要如何处理?代码示例会很好,并提供解释
  4. 只是为了确保 - 如果控制器不会捕获任何异常,在 k8s 和 docker env 中,Pod 将因状态错误而失败并重新启动 - 对吗?

What is a Fatal Exception? How can occur? VirtualMachineError, InterruptedException, LinkageError, ControlThrowable

基本上,您可以考虑致命错误 - 那些您无法正确处理的错误。例如。 VirtualMachineError 或任何其他 java.lang.Error 识别 JVM 内部发生的问题,您不能做太多事情:像 AbstractMethodError - 识别以某种方式被调用的方法没有实现,这意味着问题在字节码中。 或著名的 OutOfMemmoryError - 通常建议不要处理,因为它可能导致堆损坏或其他问题。让他们让应用程序崩溃。

Why it's not good to catch all exceptions, but only NonFatal? Because, suing case NonFatal(e) => you avoiding possible problems describe before.

In the case of Fatal Exception - how its need to be handled?, code-example would be great with an explanation

你不应该发现它们 - 致命错误你的朋友,将使故障排除更容易。让他们崩溃应用程序。这是正确的做法。

Just to make sure - If the controller will not catch any Exception, in k8s & docker env, the Pod will be failed with status Error and make a Restart - Right?

是的,但请确保您有一些 circuit breaker 逻辑 - 不要无休止地重新启动应用程序,如果这样做没有帮助。例如。如果 AbstractMethodError - 二进制文件存在问题并且修复它的唯一方法 - 重新构建或修复依赖项,但重述只会消耗资源,而不会产生结果。

我觉得看NonFatalapply方法是最好理解的:

def apply(t: Throwable): Boolean = t match {
  // VirtualMachineError includes OutOfMemoryError and other fatal errors
  case _: VirtualMachineError | _: ThreadDeath | _: InterruptedException | _: LinkageError | _: ControlThrowable => false
  case _ => true
}

来自Scaladoc

Extractor of non-fatal Throwables. Will not match fatal errors like VirtualMachineError (for example, OutOfMemoryError and WhosebugError, subclasses of VirtualMachineError), ThreadDeath, LinkageError, InterruptedException, ControlThrowable.

让我们深入探讨上面的每个异常:

  • VirtualMachineError:抛出表示 Java 虚拟机已损坏或 运行 没有继续运行所需的资源。

  • ThreadDeath:只有在异步终止后必须清理时,应用程序才应捕获此 class 的实例。如果 ThreadDeath 被某个方法捕获,重要的是重新抛出它以便线程真正死亡。

  • InterruptedException:偶尔一个方法可能希望测试当前线程是否已经被中断,如果是,就立即抛出这个异常。

  • LinkageError:{@code LinkageError} 的 Subclasses 表明一个 class 对另一个 class 有一些依赖;然而,后者class在前者class.

    编译后发生了不兼容的变化
  • ControlThrowable:用于流控制的可抛对象的父对象 class。 ControlThrowable 的实例通常不应被捕获。

如你所见,所有异常都是进程无法恢复的异常。因此,最好让那些异常冒泡,并终止进程。

用法应该是(来自我附上的NonFatal页面):

try {
  // dangerous stuff
} catch {
  case NonFatal(e) => log.error(e, "Something not that bad.")
 // or
  case e if NonFatal(e) => log.error(e, "Something not that bad.")
}