본문 바로가기
Android 개발/Kotlin

Coroutine을 이용해 Parallel한 네트워크 호출 #Kotlin

by Developer88 2020. 3. 28.
반응형

Kotlin의 Coroutine을 이용하여서 NetworkCall을 할 경우,

동시에 2개 혹은 3개의 네트워크 API를 호출해야 할 경우 어떻게 해야 할까요?

당연히 A를 먼저하고 끝나면 B를 하는 Sequential한 방법은 사용하지 않을 것이구요.

Parallel하게 동시에 호출한 다음 return된 값들을 이용할 텐데요.

오늘은 이것의 방법에 대해서 정리해 보도록 하겠습니다.

 

1. async와 successHandler

Paralllel하게 호출하여 비동기로 결과 값을 받기 위해서는,

async 코루틴 빌더를 사용하여야 하는데요.

 

1-1. async와 successHandler의 사용

 

동시에 2개의 호출을 한다고 가정해 보겠습니다.

임의의 successHandler를 만들어서 async빌더에서 return해 주는 deferred객체 두개를 인자로 넣어주고 나서,

successHandler에서 두개의 객체에 await함수를 사용해 주면 됩니다.

 

async를 두개의 CoroutineScope로 감싼 이유는,

만약 둘중 하나의 호출이 실패하여 Cancel됬을 경우,

부모 CoroutineScope의 Child인 나머지 하나도 같이 Cancel되도록,

Coroutine의 StructuredConcurrent를 이용하기 위해서 입니다.

 

 

 

결과는 다음과 같이 정상적으로 나왔습니다.

 

 

1-2. Exception 이 발생하는 경우

그럼 실제로, 두개의 네트워크 콜중 하나에 Exception일어나면 어떻게 되는지 보도록 하겠습니다.

mSecond에 throw를 해 보았습니다.

 

delay가 걸린 mFirst보다 mSecond에서 Exception이 나왓고,

Crash가 발생하였습니다.

 

Catch가 걸렸는데요. Exception이 나타나는 군요.

이것은 Coroutine의 StructuredConcurrency와도 연관이 있는데요.

async블록의 Child 코루틴에서 발생한 Exception으로 인해 취소가 되면,

부모와 그 부모의 최상단 부모그리고 다른 Child에게 까지,

전파되고 Cancel되기 때문인데요.

 

1-2. SupervisorScope를 이용한 해결방법

그래서, 부모나 child에게 Exception을 전파하지 않는 특징이 있는,

이번엔 SupervisorScope를 사용해 보겠습니다.

 

 

정상적으로 동작은 하는 군요.

그런데, 한가지 이상한 점이 있습니다.

아래 이미지와 같이,

로그를 찍어서 보니 api2Call이 찍히고 300초 딜레이 후에 api1이 호출되면서 Exception이 발생하였고,

그것을 catch해서 stack이 print 되었는데요.

결론적으로 좋은 방법이 아닌 것 같습니다.

왜냐하면, 두개의 콜이 호출되어서 실행 될때까지 다 기다리고 나서야,

Exception이 catch가 되었기 때문이지요.

 

 

 

그렇다면 다시 돌아가서,

supervisorScope없이 문제를 해결해 보아야 하는데요.

이 때 필요한 것이, CoroutineExceptionHandler입니다.

이 Coroutine은 구조상 CancellationException이외의 Exception이 throw되면,

최상단의 부모에게 까지 고자질하는 구조로 되어있기 때문에,

최상단의 부모가 ExceptionHandler를 필요로 합니다.

 

위와 같이, ExceptionHandler를 만들어서 아래와 같이 최상단 부모의 context에 추가해 주면,

정상적으로 동작하는 것을 볼 수 있습니다.

 

 

로그를 보면, supervisorScope 때와는 다르게,

저희가 원하는 결과를 보여주고 있네요.

getApi1Call을 기다리지 않고, getApi2Call에서 바로 Exception을 throw해서

catch한 다음 stack을 print 한 것을 볼 수 있습니다.

 

 

이상으로 Coroutine을 이용해서 Parallel한 네트워크 호출을 하는 방법에 대해 정리해 보았습니다.

더 좋은 방법이 있다면, 이 글에서 업데이트 하도록 하겠습니다.

 

728x90

댓글0