Last Updated:

How Kotlin arranges the completion of corutin


The article is about how Kotlin arranges the completion of corutin.



To begin with, the Job interface representing corutina has a method cancel()designed to complete the corutina. Calling it results in the following:

  • Corutina terminates at the first breakpoint, that is, when some standard suspend function is called from the standard Corutin library (in the case of the example below, this point is the method delay()).
  • If Job has descendants, then they too will be completed.
  • Job will be completed, it can no longer be used to launch new corutinus (Cancelled state).


As in this example, often after job. cancel() should be used job. join()to wait for the actual completion. This is such a common need that the Corutin support library includes an extension function cancelAndJoin().

When Job receives a completion signal, it changes its state to Cancelling. then, when it goes to the next breakpoint, it throws an exception CancellationException. This exception can be intercepted, but to avoid elusive bugs, it is better to immediately throw it again:


Due to the fact that the completion of corutina leads to the release of the exception, we can use the block finallyto correctly close all resources used by corutina (databases, files, network connections). However, we will no longer be able to run other corutins or call suspend functions in this block. These actions will be prohibited after corutina enters the Cancelling state. The only way out of this situation is to use a block withContext(NonCancellable), which will allow you to call suspend-functions, but will not respond to the completion signal:

Another way to execute the code after the corutina is complete is to use the invokeOnCompletion()that will be invoked regardless of whether the corutina was completed forcibly or it just worked out its time.

The completion of corutina occurs at stopping points. But what if there are no breakpoints (no calls to suspend functions) in the corutina code?

One option is to use the feature yield(). This suspend function will suspend the corutinus and immediately resume it, but along the way it will process the completion signal. The second option: Boolean field isActive, it is enough just to check its value and, if it is false, finish the work inside the corutina. Another option is to call the function ensureActive(). It will throw a CancellationException if the corotene has already received a completion signal.