순서를 유지하며 요청 보내기

CmplxN·2020년 11월 22일
1

요즘 세상에 어느정도 기능이 있는 앱이라면, 서버와의 통신이 없을 수 없다.
클라이언트에 수많은 데이터를 저장해둔다던가, 고성능이 필요한 연산을 실행할 수는 없기 때문이다.
그래서 안드로이드 개발의 경우 보통 OkHttp + Retrofit를 사용해서 통신을 한다.
또한 보통 RxJava 또는 CoRoutine을 이용해서 비동기 처리를한다.

순서를 맞춰야하는 개별요청

서버에 보내는 요청은 CRUD 모두 단건인 경우가 대부분이다.
혹시 단건이 아니더라도, 리퀘스트를 ListArray에 담아보낼 수 있을 것이다.
그래서 (다중 요청 + 순서 유지)의 경우도 서버단에서 알아서 처리해주기도 한다.

하지만, 일이라는 것이 언제나 마음대로 되는게 아니다보니, 클라이언트에서 이 모든 것을 해결해야할 수도 있다.
그러니까 다중 요청을 복수의 단건 요청으로 처리하면서 순서유지까지 해야할 수도 있다.

그러면 이미지를 단건으로 나누어서 업로드 요청을 하고 그 결과의 순서를 유지하는 시나리오를 생각해보자.

  1. 복수의 이미지를 개별로 서버에 업로드 요청을 보낸다.
  2. 이미지 업로드 단건 요청의 결과로 업로드된 이미지의 url이 전달된다.
  3. 그리고 이 이미지 url들을 순서에 맞춰서 하나의 List로 만든 다음 재사용한다.

해결책 찾기

RxJava를 사용해왔다면 이런 경우 속칭 국밥인 flatMap을 생각할 수 있다.
그러나 flatMap는 결과물의 순서를 보장하지 못한다.
그러므로 순서를 맞추려면 별도의 작업이 필요하다.
예를 들면, 아이템의 순서를 별도로 저장해뒀다가 나중에 정렬할 수 있을 것이다.
예를 들면, Pair<Item, Int>로 RxChain을 타다가 필요할 때 Pair.second를 기준으로 정렬한다.

하지만 그런식으로 구현할 경우, 가독성에도 안좋고, 별도로 정렬도 해야하므로 결코 좋다고 할 수 없다.
그래서 이번에는 concatMap를 사용해보자.
쉽게 생각하면 concatMap은 순서를 맞춰주는flatMap이라고 생각하면 된다.
그러므로 아래와 같이 코딩하면 된다. (가볍게 의미만 읽어주면 된다.)

Observable.fromIterable(imageFiles)
    .concatMapSingle {
        api.uploadImage(it.toMultiPart())
    }
    .toList()

개선해보기

하지만 위처럼 구현하면 flatMap에서 누릴 수 있던 단점 하나를 포기하게 된다.
concatMap을 쓰면, 순서를 맞춰야 하는 점 때문인지 요청이 병렬적으로 가지 않는다.
concatMap을 쓰면 실질적으로는 Non-Blocking이 아니라 Blocking이 된다.
이러면 서버 응답을 기다리지 않고 요청을 보낼 수도 있다는 점에서 비효율이 발생할 수 있다.

그래서 이번엔 concatMapEager를 사용해보자.
concatMapEagerconcatMap과 같은 결과를 내지만, 한번에 source를 전부 subscribe한다.
다른 점은 내부적으로 buffer를 이용, 순서를 맞춰서 결과를 배출한다.
참고로 concatMapEager의 경우 concatMap과 달리, concatMapEagerSingle같은건 없다.
그러므로 SingletoObservable()을 걸어주자.

Observable.fromIterable(imageFiles)
    .concatMapEager {
        api.uploadImage(it.toMultiPart()).toObservable()
    }
    .toList()
profile
Android Developer

0개의 댓글