abbic
07/03/2024, 10:29 AMsuspend fun joinAll(vararg blocks: suspend () -> Unit) = supervisorScope {
blocks.map {
launch { it() }
}.joinAll()
}
its for launching multiple jobs in parallel inside any suspend fun, and waiting until theyre completed/failed before moving forward.
Something strange that's happening is that jobs called this way that crash don't seem to get caught properly, ie
try {
joinAll(
{ throw NoSuchElementException }
)
println("continue as normal") // this doesnt run
} catch(e: NoSuchElementException) {
// this doesnt run, app crashes instead
}
doesnt the supervisorScope imply that the child being launched should fail gracefully, and the println statement should run? and given that it crashes instead, why isnt the exception being caught?abbic
07/03/2024, 10:37 AMephemient
07/03/2024, 10:38 AMA failure of a child job that was created using launch can be handled via CoroutineExceptionHandler in the context.
ephemient
07/03/2024, 10:40 AMabbic
07/03/2024, 10:40 AMephemient
07/03/2024, 10:40 AMephemient
07/03/2024, 10:41 AMasync
instead of launch
abbic
07/03/2024, 10:42 AMstreetsofboston
07/03/2024, 12:26 PMephemient
07/03/2024, 1:09 PMasync
throws, the exception gets captured in that Deferred
instead of going to the scope's CoroutineExceptionHandlerephemient
07/03/2024, 1:10 PMawaitAll()
might not have the behavior you want there though, since it'll cancel remaining deferred if one of them is failedabbic
07/03/2024, 1:11 PMabbic
07/03/2024, 1:12 PMephemient
07/03/2024, 1:13 PMephemient
07/03/2024, 1:14 PMsuspend fun joinAll(vararg blocks: suspend () -> Unit) {
val exceptions = supervisorScope {
blocks.map {
async { it() }
}
}.mapNotNull { it.getCompletionExceptionOrNull() }
when (exceptions.size) {
0 -> return
1 -> throw exceptions.first()
else -> throw RuntimeException("multiple exceptions").apply {
for (exception in exceptions) addSuppressed(exception)
}
}
}
streetsofboston
07/03/2024, 1:15 PMstreetsofboston
07/03/2024, 1:15 PMstreetsofboston
07/03/2024, 1:16 PM