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)