Cancel on Job doesn't cancel scope, if Dispatcher context was overwritten
See original GitHub issueI use coroutines for any asyn action in my applications, but also I wanted to test my classes, so I wrote small abstraction for Dispatchers:
object DispatcherProvider {
var IO: CoroutineContext = Dispatchers.IO
private set
var Main: CoroutineContext = Dispatchers.Main
private set
var Default: CoroutineContext = Dispatchers.Default
private set
fun enableTesting(coroutineScope: CoroutineScope) {
IO = coroutineScope.coroutineContext
Main = coroutineScope.coroutineContext
Default = coroutineScope.coroutineContext
}
}
In tests I just use it like this:
runBlocking {
DispatcherProvider.enableTesting(this)
// code that call classes which are using Coroutines
}
// all async code will be done here
Everything worked well, but recently I had to test class, which implemented CoroutineScope:
class SomeClass():CoroutineScope{
private val scopeJob by lazy { Job() }
override val coroutineContext: CoroutineContext by lazy { DispatcherProvider.Main + scopeJob }
fun release(){
scopeJob.cancel()
}
}
In my tests when I called cancel on scopeJob, scope was still active, and none of async call were stopped. I’m not sure if it is a bug, or I just don’t understand something, but I hope someone can help me. btw. coroutines rocks!
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:7 (3 by maintainers)
Top Results From Across the Web
Kotlin Coroutine Job Hierarchy — Succeed, Fail, and Cancel
Even after a cancellation, the parent coroutine still hasn't completed until all of its children are completed.
Read more >Coroutines: first things first - Medium
The ongoing work (running coroutines) can be canceled by calling scope.cancel() at any point in time. You should create a CoroutineScope ...
Read more >What is the difference Job.Cancel vs Scope.Cancel in ...
In your first code block, your Job does not cooperate with cancellation. It has an infinite loop and does not call any suspend...
Read more >Coroutines (Part II) – Job, SupervisorJob, Launch and Async
val scope = CoroutineScope(Dispatchers. ... When a parent's job is canceled, the children's jobs are canceled;; If we cancel the child's job ......
Read more >Improve app performance with Kotlin coroutines
In Kotlin, all coroutines must run in a dispatcher, even when they're ... Cancel the coroutine started above, this doesn't affect the scope...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Thanks for your answer! I was referring to Chris Banes talk about Android Suspenders, where he showed how to use CoroutineScope and he did cancel it with “job.cancel()”
By “scope is not cancelled” I ment, that “isActive” flag is set to true. Whole example (DispatcherProvider is the class from my first comment:
2.SomeTest
Console output after running test: In for loop 0 Calling release In for loop 1 In for loop 2 In for loop 3 In for loop 4 In for loop 5 In for loop 6 In for loop 7 In for loop 8 In for loop 9 In for loop 10 Finished with true
java.lang.AssertionError: Assertion failed
As you can see, after calling release my scope still “isActive”. Did I understand Chris wrong? Cancelling job doesn’t cancel scope? If so, why do we need this job anyway?
@EarthyOrange, I couldn’t reproduce the behavior you describe.
For me, this prints
going to sleep...
only once.