hey everyone. I need an advice on implementation o...
# coroutines
o
hey everyone. I need an advice on implementation of supervisorScope.
Copy code
suspend fun filterNonDisplayableActions(allActions: List<Action>, context: Context): List<Action> {
        return allActions
            .filter {
                supervisorScope {
                    async {
                        canDisplay(it, context)
                    }
                }.await()
            }
    }

    suspend fun canDisplay(action: Action, context: Context): Boolean {
        val actionVisibility = getActionVisibilityClass(action)
        return try {
            withTimeout(100) {
                actionVisibility.isVisibleInCatalog(context)
            }
        } catch (e: Exception) {
            actionVisibility.defaultVisibility()
        }
    }
I’m trying to iterate on over the list and call
canDisplay
on each element using the async/await mechanism to get all result in the end. Do I do it in right way or should I play around with
.awaitAll()
And what would be the best way to test it? Thanks in advance!
1
s
What are you trying to achieve? At the moment, your implementation is pretty much equivalent to just writing:
Copy code
return allActions.filter { canDisplay(it, context) }
Adding the
supervisorScope
and `async`/`await` doesn’t change how the code behaves, because you always wait for the job to complete before proceeding to the next one.
o
the intention is to run
canDisplay()
in parallel. and once all of those are executed - filter the
allActions
list
👍 1
what I was thinking is that
async
will start a coroutine for each element
s
Your previous message expresses the problem well: in order to parallelise the async jobs, this actually needs to be done in two steps: 1. launch all the async operations 2. await the results and filter the list That makes using
filter
a little bit tricky, but you could take a shortcut by using
null
for the non-matching values. Something like this:
Copy code
coroutineScope {
    allActions.map { action -> 
        async { 
            action.takeIf { canDisplay(action, context) } 
        }
    }.awaitAll().filterNotNull()
}
This is basically emulating the behaviour of
filter
by using
takeIf
followed by
filterNotNull
So for step 1 you get a
List<Deferred<Action?>>
, which represents the coroutines running in parallel. Then step 2 is
awaitAll().filterNotNull()
which waits for the results and removes the ones that didn’t match.
o
got a compilation error, which is a bit confusing to me
s
Sorry, that’s my mistake. The
action ->
part should have been after the
map {
, not the
async {
I’ll edit my previous post to correct it
o
ah, got it! Thanks a lot for explanation!
additional question to the topic is there a way to test it properly? That there are multiple coroutines starting cc @Sam
s
If you can mock out the
isVisibleInCatalog
implementation, you could have it increment a counter and then
awaitCancellation()
. Then you can inspect the counter to see how many coroutines are currently calling that function. After that, advance the virtual time so the timeouts fire and the test completes normally.
thank you color 1