我正在大量使用协程来创建服务,但是我面临着一个关于将异常从服务内部转换到外部的问题。下面是我想在没有协程的情况下做的事情的综合(下面是操场上的完整示例:
class MyService {
fun myBigComputation(type: MyServiceType) {
try {
for (i in (0..10_000)) {
mySubComputation(type, i)
}
} catch (e: LowLevelException) {
throw HighLevelException(type, e)
}
}
private fun mySubComputation(type: MyServiceType, i: Int) {
...
// something bad happend
throw LowLevelException(type)
}
...
}
您可以看到我正在将LowLevelException转换为HighLevelException。在协程上下文中,最好的方法是什么?
不工作,因为LowLevelException使所有结构失败,直到supervisorScope Playground
suspend fun main() = coroutineScope {
val service = MyService()
supervisorScope {
for (type in MyService.MyServiceType.values()) {
launch(CoroutineExceptionHandler { _, e ->
if (e is HighLevelException) {
println("ERROR: ${e.message}")
}
}) {
service.myBigComputation(type)
}
}
}
}
class MyService {
suspend fun myBigComputation(type: MyServiceType) = coroutineScope {
launch(CoroutineExceptionHandler { _, e ->
if (e is LowLevelException) {
throw HighLevelException(type, e)
}
}) {
for (i in (0..10)) {
mySubComputation(type, i)
}
}
}
private fun mySubComputation(type: MyServiceType, i: Int) {
if (i < 5 || type != MyServiceType.type1) {
print(".")
} else {
// something bad happend
println("something bad happened but exception kill all")
throw LowLevelException(type)
}
}
class LowLevelException(val type: MyServiceType): Exception()
enum class MyServiceType {
type1,
type2,
type3
}
}
class HighLevelException(val type: MyService.MyServiceType, e: Exception): Exception("Exception for type $type", e)
我是这么做的,但我很确定有更好的方法,不是吗?Playground
suspend fun main() = coroutineScope {
val service = MyService()
supervisorScope {
for (type in MyService.MyServiceType.values()) {
launch(CoroutineExceptionHandler { _, e ->
if (e is HighLevelException) {
println("ERROR: ${e.message}")
}
}) {
service.myBigComputation(type)
}
}
}
}
class MyService {
suspend fun myBigComputation(type: MyServiceType) = supervisorScope {
launch(CoroutineExceptionHandler { _, e ->
if (e is LowLevelException) {
throw HighLevelException(type, e)
}
}) {
for (i in (0..10)) {
mySubComputation(type, i)
}
}
}
//...
}
1条答案
按热度按时间kqlmhetl1#
你试图使用CoroutineExceptionHandler来处理这个问题,这会使它变得过于复杂。CoroutineExceptionHandler是用于未捕获的异常的。当它被调用时,你的协程已经抛出并失败了。它被设计成一个非常高级的行为,有点像Java中的
uncaughtExceptionHandler
,如果你熟悉的话。但是,您也将CoroutineExceptionHandler附加到子协程。在 child 协程上设置CoroutineExceptionHandler没有任何效果,因为它只用于处理未捕获的异常,并且子协程将异常传播给其父协程。请参阅此处文档的第二段以了解解释。
因此,您的代码应该看起来更像: