mboudraa
02/21/2022, 3:15 PMStore
which is essentially a wrapper on top of 2 flows. From this store I can dispatch events and those events will trigger coroutines to be executed on a given scope.
However when I cancel the scope, the coroutines aren't cancelled...
suspend fun dispatch(action: Action) {
val currentState = stateFlow.value
_actionFlow.tryEmit(action)
supervisorScope {
sideEffects.forEach { sideEffect ->
launch {
sideEffect(currentState, action)?.let { dispatch(it) }
}
}
}
}
Here's how my test is written
@Test
fun should_cancel_side_effect() = runTest {
launch {
val store = createStore(this) {
registerSideEffect sideEffect { _, action ->
if (action !is TestAction.Add) return@sideEffect null
delay(1_000)
return@sideEffect TestAction.Remove(3)
}
}
store.stateFlow.test {
CoroutineScope(Job()).launch childScope@{
store.dispatch(TestAction.Add(3))
cancel()
}.join()
assertEquals(TestCounterState(0), awaitItem())
this@launch.cancel()
}
}.join()
}
But the side effect returns the TestAction.Remove(3)
like I never called cancel()
on the scope that launched the coroutineNick Allen
02/21/2022, 8:16 PMregisterSideEffect sideEffect { _, action ->
? Is it dispatch
or suspendDispatch
? Does dispatch
launch a coroutine that calls suspendDispatch
? Please ensure code samples have sufficient info for others to understand what's going on. Linking to examples on https://play.kotlinlang.org can help a lot.
3. Job()
does not create a child job. It creates a Job
with no parent. I suspect this or similar issue is the root of your misunderstanding.
4. I can't think of a reason you'd ever want to call CoroutineScope(...).launch {...}
. CoroutineScope
function is generally used to create a CoroutineScope
that is saved to a member property and represents the lifetime of the instance and is cancelled when the object is closed/cancelled so all work launched from that CoroutineScope
can be cancelled.mboudraa
02/21/2022, 8:51 PMsuspendDispatch
and dispatch
are the same thing it's a typo that remained while I was trying stuff. (FIxed)
3. 4. I'm trying to simulate that the coroutine is launched from another parent with a very different scopeNick Allen
02/21/2022, 10:35 PMsupervisorScope
waits for child jobs to finish (as any suspend method should)? So the side effects are all completely done by the time dispatch
returns. If you want dispatch
to start work, but not finish, then it should not suspend and instead take a CoroutineScope
as a parameter in order to launch/async
the work.mboudraa
02/21/2022, 11:29 PMgildor
02/22/2022, 4:15 AMI’m trying to simulate that the coroutine is launched from another parentIt doesn’t look as the most clean way to do this, keep all your coroutines childs of parent job, and just launch new coroutine using standard launch (it creates own scope with child job)