wanna be dev 🧑‍💻

Cool 하고 Sick한 개발자가 되고 싶은 uzun입니다

A.K.A. Kick-snare, hyjhyj0901, h_uz99 solvedac-logo

Android/Issue Handling

순서보장 비동기 작업에 대한 고찰

Kick_snare 2024. 7. 24. 13:55
728x90

상황

  • Node.js 프레임워크로 돌아가는 서버
  • WebRTC 구축을 위해 MediaSoup을 사용
  • 통신을 위해 socket.io 를 사용하고 있다.

문제점

  • socket.io 에서, 클라이언트에서 이벤트를 emit 하면 callback으로 응답을 주는 API의 경우
  • callback으로 응답 된 데이터를 바로 다음에 사용해되는 경우
  • callback이 호출될때까지 대기해야함 → 즉 순서가 보장되어야한다.

 

시도한 방법

0. 고전적인 방법 : Callback Hell

  • callback안에 다음으로 실행할 코드를 적으면 되긴하지만 콜백지옥을 불러오고 싶지는 않음
  • 심미적으로 불편

 

1. 단순하게 동기로 받아오기

  • (socket.on의 람다 식이 callback의 listener)
  • 소비 시점에 따라 res가 할당 되어 있을지, emptyString인지 랜덤이다.
  • 비동기적 처리의 필요성을 느낌

 

2. async - await를 활용하여 deferred 객체로 대기한다.

  • await 하더라도 소비하는 시점이 callback 오기 전인 경우가 있었다.
  • 따라서 deferred 객체는 소비 시점에서 초기화되지 못했다.
  • lateinit property deferred has not been intialized

 

3. Flow를 활용하여 시도

  • 비슷하게 flow로 시도하여 collect로 소비할려고 시도
  • 마찬가지로 flow 또한 collect하는 시점에 초기화 되지 못했다.
  • 소비 시점 또한 비동기 적이여야 할 것같다.

 

4. Channel로 미리 객체를 정의해보자

  • 2,3번의 경우 소비 시점에 객체가 초기화 되지 않았었다.
  • 그렇다면 아예 비동기 pipeline을 미리 만들고 데이터를 보낸다면?
  • 데이터 생산 전에 channel을 미리 초기화하고 소비
  • → 되는거 같은데 왔다리 갔다리 한다.

 

5. suspendCoroutine 로 callback이 호출될 때 까지 정지

  • suspendCoroutine 또는 suspendCancellableCoroutine 을 사용하면 scope안의 코드가 실행되지만 인자로 전달되는 객체를 통해 값이 resume 될 때까지 suspend한다.
  • 즉 callback이 호출되어 resume 될때까지 대기하게 된다.
  • 서버가 응답이 없다면 영원히 suspend할 것이기에 suspendCancellableCoroutine 과 withTimeOut 을 사용하여 시간 제한을 두고, 예외처리하여 exception을 throw 한다.
  • 코드 depth가 너무 길어지고 가독성이 좋지 않아 suspendCancellableCoroutine 과 withTimeOut 를 동시에 사용할 수 있는 util function을 작성
  • 같은 코드이지만 훨씬 깔끔해보인다.

 

아직 궁금하다

  • 결국 마지막 방법은 받아올때까지 suspend한다는 것인데 병렬적으로 실행하고 소비 시점에만 await하는 방법은 없을까?
  • suspendCoroutine 은 단발성 데이터인데 만약 callback이 데이터의 시퀀스로 들어온다면?
    • callbackFlow? (channel로 구현되고 있는듯함)
  •  
728x90