If you need to make 4 API calls concurrently, but 1 of the API calls depends on data from another. W...
r
If you need to make 4 API calls concurrently, but 1 of the API calls depends on data from another. What would be the best pattern?
Copy code
fun getLiveGameData(viewScope: CoroutineScope) {
    viewScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {

        while (isActive) {
            // make the 4 API calls concurrently
            val fixture = async { payPerViewRepository.getNextFixture() }
            val liveVideo = async { payPerViewRepository.getPPVLiveVideo()?.liveVideo }
            val showLiveGame = async { payPerViewRepository.getPPVToggle()?.showVideo == 1 }
            val liveMatchInfo = async {
                // get id from Fixture first to make API call for live info
                val matchId = fixture.await()?.id.orEmpty()
                payPerViewRepository.getLiveMatchInfo(matchId)
            }

            val data = PayPerViewLiveGame(
                liveVideo = liveVideo.await(),
                fixture = fixture.await(),
                liveMatchInfo = liveMatchInfo.await(),
                showVideoPlayer = showLiveGame.await()
            )

            liveGameData.postValue(data)


            delay(Duration.ofSeconds(10).toMillis()) // poll every 10 secs
        }
    }
my current code ⬆️
the 4th API call
liveMatchInfo
relies on the first API call that returns a
fixture
object
is this a good pattern? or should I just use something like this:
Copy code
val liveVideo = async { payPerViewRepository.getPPVLiveVideo()?.liveVideo }
val showLiveGame = async { payPerViewRepository.getPPVToggle()?.showVideo == 1 }
val fixture = payPerViewRepository.getNextFixture() // suspend here to wait for result
val liveMatchInfo = async {
                // get id from Fixture first to make API call for live info
                val matchId = fixture.id.orEmpty()
                payPerViewRepository.getLiveMatchInfo(matchId)
            }
In that case the coroutine will suspend until
payPerViewRepository.getNextFixture()
returns
so maybe less performant?
k
what about moving
fixture
to same async call, where it is needed as argument?
Copy code
val liveMatchInfo = async {
                val fixture = payPerViewRepository.getNextFixture()
                val matchId = fixture.id.orEmpty()
                payPerViewRepository.getLiveMatchInfo(matchId)
            }
r
then async no longer returns deferred
c
i think all 3 versions perform the same
k
then async no longer returns deferred
Not exactly following, You mean call to
async {}
won’t return you Deferred?
r
I need the fixture object outside of the asycn scope too
k
ah, make sense, haven’t notices it’s required in other
async
too
then I think, like Christoph said, it’d perform the same
c
i think the most readable version is to make only the
liveVideo
and
showLiveGame
calls async
r
I have this now
message has been deleted
c
hmm but that code assumes that await returns null when its not ready, but await waits until the result is ready
r
all API calls return null when an error comes back
c
ah ok
r
maybe `liveMatchInfo`doesn't need to be an async coroutine
👆 1
c
you can just make liveMatchInfo not async, because you start it async and then await it
✔️ 1
r
since it's the last call and
liveVideo
and
showLiveGame
are already running concurrently right?
c
or in other words because
async { xxx()} .await()
is the same as
xxx()
r
yes, true. Thnx
👍 1
u
Why not treat it as 3 concurrent ones?
r
whats your suggestion to make it better?
u
I didnt read the whole thing but Id treat it as
concurrent(a, b, sequential(c,d))
u
I’d go with the first version as it is most straight forward. all four async, all four awaited where ever they are needed. No deeper knowledge about any details needed to understand what’s going on. No reasoning why one of those can be just a suspend call. No reasoning to break if you change the order of fiering those requests.