项目反应器:我的应用程序在 OOM 错误后继续工作,我无法拦截和处理此类错误



我注意到项目reactor不允许处理OOM错误。项目反应器开发人员通过添加日志消息来拦截和处理此类错误,但没有办法为框架用户拦截和处理这些错误。

我想这可能是个大问题。如果发生OOM,我的应用程序客户端发送的HTTP请求会挂起,但我的应用软件会继续工作并处理其他请求,我的程序的健康检查也会成功。

正如我在GitHub上的一条评论中所回答的那样,我的应用程序可能处于不可恢复的状态。是的,我同意,我更希望在OOM发生时健康检查失败或应用程序完成。我知道onError方法不是处理这种特殊错误的好方法。但在我看来,这可以在类Hooks中完成,例如onJvmError,这将允许优雅地启动关闭过程,或者通过实现有关这种情况的健康检查来发出信号。

我用Kotlin(Java(和rest端点实现了这个项目,使用reactor和Webflux来重现这种情况。

interface CsvRepository : ReactiveCrudRepository<CsvRow, Long>
@Service
class CsvService(val csvRepository: CsvRepository) {
fun createByteArray(): Mono<ByteArray> =
csvRepository.findAll()
.reduce(ByteArrayOutputStream()) { output, el ->
output.write(el.toString().toByteArray())
output.write("n".toByteArray())
output
}
.map { it.toByteArray() }
}
@SpringBootApplication
class WebfluxMemoryRetroProjectApplication(val csvService: CsvService) {
@Bean
fun routing(): RouterFunction<ServerResponse> = router {
accept(MediaType.ALL).nest {
GET("/test") {
csvService.createByteArray()
.flatMap { result ->
ServerResponse.ok()
.headers { httpHeaders ->
httpHeaders.contentType = MediaType("application", "force-download")
httpHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=test.txt")
}
.bodyValue(ByteArrayResource(result))
}
}
}
}
}

作为HTTP GET请求的结果,它从数据库中请求数据,并创建一个大小约为70MB的文件。因此,如果我用-xmx100m运行它,我在日志中只有一个错误:

2022-02-07 12:25:06.135 ERROR 10288 --- [actor-tcp-nio-1] r.n.channel.ChannelOperationsHandler     : [7edd71ea, L:/127.0.0.1:58918 - R:localhost/127.0.0.1:5432] Error was received while reading the incoming data. The connection will be closed.
java.lang.OutOfMemoryError: Java heap space
....

2022-02-07 12:25:06.141 ERROR 10288 --- [actor-tcp-nio-1] i.r.p.client.ReactorNettyClient          : Connection Error
reactor.netty.ReactorNetty$InternalNettyException: java.lang.OutOfMemoryError: Java heap space

此错误未得到处理,HTTP客户端请求挂起。这是预期的行为吗?如何处理此异常?我尝试过onErrorResumeHooks.onOperatorError,但无法拦截这种类型的异常。应用程序一直在工作,而我无法拦截和处理这样的错误,这对我来说似乎不合乎逻辑。

我试图找到更好的东西。同样,在发生OutOfMemory错误后,我的应用程序挂起,队列上的消息保持";未激活";健康检查保持正常工作并返回200。

我发现的最好的选择是设置JVM属性-XX:+CrashOnOutOfMemoryError,这样一旦出现此错误,JVM就会退出并返回代码1并记录一条消息。

我希望有一种方法来处理这些事件,例如,将有问题的消息重定向到另一个队列。

最新更新