Backend/Kotlin
테스트 코드로 이해해보는 코루틴 예외처리
findmypiece
2023. 2. 11. 01:02
728x90
@Test
fun `코루틴은 논블로킹으로 실행된다`(){
/*
코루틴 내부의 코루틴은 각각 논블로킹으로 처리된다.
단, 스레풀에서 돌렸을 때 이야기..
메인스레드 하나에서 돌리면 작업자가 한명이니 당연히 순차처리된다.
*/
runBlocking(Dispatchers.IO) {
launch {
repeat(1000){
println("1111111")
}
}
launch {
repeat(1000){
println("2222222")
}
}
}
}
@Test
fun `코루틴은 기본적으로 예외가 부모로 전파된다`(){
/*
예외가 부모로 전파되면 부모가 취소되고 결국 다른 형제 코루틴도 취소된다.
launch, async 동일
*/
runBlocking(Dispatchers.IO) {
launch{
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
@Test
fun `예외를 부모로 전파하지 않으려면 SupervisorJob을 사용해야 한다`(){
runBlocking(Dispatchers.IO) {
launch(SupervisorJob()) {
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
@Test
fun `예외를 부모로 전파하지 않는 방법으로 코루틴 내부를 try catch 로 래핑하는 방법도 있긴하다`(){
runBlocking(Dispatchers.IO) {
launch {
try{
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}catch (e: Exception){
println("캐치함 ${e.message}")
}
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
@Test
fun `하지만 코루틴 바깥에 정의된 try catch 에서는 예외를 잡지 못한다`(){
/**
* async 도 마찬가지다.
* 이러한 특성 때문에 try catch 로 예외 전파를 막으려면
* 모든 코루틴 내부를 try catch 로 래핑해야 하는 문제가 생긴다.
*/
runBlocking(Dispatchers.IO) {
try{
launch {
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}
}catch (e: Exception){
println("캐치함 ${e.message}")
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
@Test
fun `supervisorScope 블록을 이용하면 해당 블록 내의 코루틴은 모두 SupervisorJob을 사용하게 된다`(){
runBlocking(Dispatchers.IO) {
supervisorScope{
launch{
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
}
/**
* 예외전파는 SupervisorJob 으로 막았는데 핸들링은 어떻게 할 수 있을까?
* 예외를 핸들링 하려면 어쨋든 예외를 잡아야 한다.
*/
@Test
fun `launch 에서 발생된 예외를 캐치하려면 CoroutineExceptionHandler 람다를 사용해야 한다`(){
runBlocking(Dispatchers.IO) {
supervisorScope{
launch(
CoroutineExceptionHandler{context, ex ->
println("${ex.message} 에 대한 후처리입니다")
}
){
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
}
@Test
fun `async 에서 발생된 예외는 await() 호출시 try catch 로 캐치하면 된다`(){
runBlocking(Dispatchers.IO) {
supervisorScope{
try {
async{
repeat(100){
println("첫번째 $it")
if(it == 2){
throw RuntimeException("1111111 Error")
}
}
}.await()
}catch(e: Exception){
println("${e.message} 에 대한 후처리입니다")
}
launch {
repeat(100){
println("두번째 $it")
}
}
}
}
}
728x90