How does scope track coroutine cancellation?
sobes.tech AI
Answer from AI
Scope tracks coroutine cancellation using a Job object. Each CoroutineScope has an associated Job.
When a new coroutine is created within a CoroutineScope, it inherits the Job from that scope as its parent Job.
The cancellation tracking mechanism works as follows:
- Scope Cancellation: When
cancel()is called on aJobscope, it recursively cancels all its childJobs. - Child Coroutine Cancellation: When a child coroutine is canceled (for example, via
withContext(NonCancellable)) or an unhandled exception occurs, it reports this to its parentJob. The parentJob(of the scope) can then cancel other child coroutines. - Cooperative Cancellation: Coroutines should be cooperative regarding cancellation. This means that within a coroutine, the code should periodically check whether it has been canceled to terminate its work properly. Standard suspend functions (like
delay, I/O operations) automatically check theJob's state.
Code can explicitly check for cancellation using isActive or ensureActive():
// Example of checking coroutine activity
suspend fun fetchData() = coroutineScope {
launch {
while (isActive) {
// Perform some long operation
delay(100) // suspension point - automatically checks for cancellation
// Or explicitly check
if (!isActive) {
break // Exit loop on cancellation
}
}
println("fetchData coroutine completed")
}
}
Using ensureActive() throws a CancellationException when canceled:
// Using ensureActive()
suspend fun processData() {
// ... some work ...
ensureActive() // Throws CancellationException if coroutine is canceled
// ... continue work only if coroutine is active ...
}
CancellationException is the standard way to propagate a cancellation signal. It should not be considered an error in the context of coroutine cancellation.
Scope, owning a Job, creates a hierarchy of "parent-child" Jobs, which allows cancellation signals to propagate from parent to children. This is a cornerstone of structured concurrency in coroutines.