Last active
November 9, 2020 12:01
-
-
Save DrMetallius/06655c456e5ef60ea74d6b11ddc5d050 to your computer and use it in GitHub Desktop.
Exceptions in coroutines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import kotlinx.coroutines.CancellationException | |
import kotlinx.coroutines.CoroutineExceptionHandler | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Dispatchers | |
import kotlinx.coroutines.SupervisorJob | |
import kotlinx.coroutines.async | |
import kotlinx.coroutines.delay | |
import kotlinx.coroutines.launch | |
import kotlinx.coroutines.plus | |
import kotlinx.coroutines.runBlocking | |
val scope = CoroutineScope(Dispatchers.Default) | |
val supervisorScope = scope + SupervisorJob() | |
val exceptionHandler = CoroutineExceptionHandler { _, throwable -> println("Caught exception: $throwable") } | |
/* | |
* - Если есть родитель - всегда в него | |
* - Если есть CoroutineExceptionHandler - используется он | |
* - Если async, оборачивает в результат | |
* - Иначе выбрасывается | |
* | |
* Когда ловите исключения в отменяемых сопрограммах, пропускайте CancellationException | |
* supervisorScope, когда нужно, чтобы одна сопрограмма не останавливала другую | |
*/ | |
fun main() = runBlocking { | |
runLaunch() | |
} | |
suspend fun runLaunch() { | |
val job = scope.launch { failingTask() } | |
job.join() | |
} | |
suspend fun runAsync() { | |
val deferred = scope.async { failingTask() } | |
deferred.join() | |
} | |
suspend fun runNestedLaunch() { | |
val job = scope.launch { | |
launch { failingTask() } | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithHandler() { | |
val job = scope.launch(exceptionHandler) { | |
launch { failingTask() } | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithHandlerInside() { | |
val job = scope.launch { | |
launch(exceptionHandler) { failingTask() } | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
} | |
job.join() | |
} | |
suspend fun runNestedAsync() { | |
val job = scope.launch { | |
val deferred = async { | |
failingTask() | |
true | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
println("Result: ${deferred.await()}") | |
} | |
job.join() | |
} | |
suspend fun runNestedAsyncWithTryCatchIncorrectly() { | |
val job = scope.launch { | |
val deferred = async { | |
failingTask() | |
true | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
val result = try { | |
deferred.await() | |
} catch (ex: Exception) { | |
println("Caught $ex") | |
false | |
} | |
println("Result: $result") | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithTryCatchIncorrectly() { | |
val job = scope.launch { | |
try { | |
launch { failingTask() } | |
} catch (ex: Exception) { | |
println("Caught $ex!") | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithTryCatchWithoutCancellation() { | |
val job = scope.launch { | |
launch { | |
try { | |
failingTask() | |
} catch (ex: Exception) { | |
println("Caught $ex") | |
} | |
println("At least we tried!") | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithTryCatchWithoutCancellationHandlingAndCanceling() { | |
val job = scope.launch { | |
val innerJob = launch { | |
try { | |
failingTask() | |
} catch (ex: Exception) { | |
println("Caught $ex!") | |
} | |
println("At least we tried!") | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
innerJob.cancel() | |
} | |
job.join() | |
} | |
suspend fun runNestedLaunchWithTryCatchAndCanceling() { | |
val job = scope.launch { | |
val innerJob = launch { | |
try { | |
failingTask() | |
} catch (ex: Exception) { | |
if (ex is CancellationException) throw ex | |
println("Caught $ex!") | |
} | |
println("At least we tried!") | |
} | |
launch { heavyTask() } | |
launch { veryHeavyTask() } | |
innerJob.cancel() | |
} | |
job.join() | |
} | |
suspend fun runOnRegularScope() { | |
val job = scope.launch { failingTask() } | |
val otherJob = scope.launch { heavyTask() } | |
job.join() | |
println("Waiting for the job") | |
otherJob.join() | |
println("Waiting for the other job") | |
} | |
suspend fun runOnSupervisorScope() { | |
val job = supervisorScope.launch { failingTask() } | |
val otherJob = supervisorScope.launch { heavyTask() } | |
job.join() | |
println("Waiting for the job") | |
otherJob.join() | |
println("Waiting for the other job") | |
} | |
suspend fun heavyTask() { | |
delay(5000) | |
println("Heavy task finished!") | |
} | |
suspend fun veryHeavyTask() { | |
delay(15000) | |
println("Very heavy task finished!") | |
} | |
suspend fun failingTask() { | |
delay(1000) | |
throw Exception("It failed!") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment