Cancellation

Basic cancellation

The Job interface has a cancel method, which allows its cancellation. Calling it triggers the following effects:

  • Cancelled coroutine ends the job at the first suspension point (example: delay).
  • If a job has some children, they are also cancelled (but its parent is not affected).
  • Once a job is cancelled, it cannot be used as a parent for any new coroutines. It is first in the “Cancelling” and then in the “Cancelled” state.

Basic example cancellation:

suspend fun main(): Unit = coroutineScope {
  val job = launch (CoroutineName("job")){
    repeat(1_000) { i ->
      delay(200)
      out.info("Printing $i")
    }
  }

  delay(1100)
  job.cancel()
  
  // JOIN is important, to make sure cancellation is complete. 
  job.join()

  out.info("Cancelled successfully")
}
GT-Sandbox-Snapshot

Code

package com.glassthought.sandbox

import gt.sandbox.util.output.Out
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

val out = Out.standard()

suspend fun main(): Unit = coroutineScope {
  val job = launch (CoroutineName("job")){
    repeat(1_000) { i ->
      delay(200)
      out.info("Printing $i")
    }
  }

  delay(1100)
  job.cancel()
  job.join()

  out.info("Cancelled successfully")
}

Command to reproduce:

gt.sandbox.checkout.commit aad4f965c9769347302e \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

[elapsed:  268ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:job] Printing 0
[elapsed:  487ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:job] Printing 1
[elapsed:  692ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:job] Printing 2
[elapsed:  896ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:job] Printing 3
[elapsed: 1101ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:job] Printing 4
[elapsed: 1147ms][tname:DefaultDispatcher-worker-1/tid:20][coroutine:unnamed] Cancelled successfully