liveBook · Manning

SupervisorJob

As explained in Kotlin in Action, 2E

SupervisorJob is a coroutine Job implementation that prevents failure of one child coroutine from automatically cancelling its sibling coroutines.

SupervisorJob is a Job for a coroutine scope whose children may fail independently. With a regular Job, an uncaught child exception fails the parent, cancels sibling coroutines, and continues up the coroutine hierarchy. A SupervisorJob keeps the parent and its other children running instead. Use it when concurrent tasks share a lifecycle but not a single all-or-nothing result, such as long-running application components or UI work. section 18.2 section 18.2.3

Attach a supervised scope to a component

Create a standalone scope with a dispatcher plus SupervisorJob, launch work through that scope, and cancel the scope when the component stops. Cancellation still reaches every child; supervision changes failure propagation, not lifecycle ownership. private val scope = CoroutineScope(dispatcher + SupervisorJob()) fun start() { scope.launch { while (true) { delay(500.milliseconds); log("Working") } } scope.launch { log("One-off task"); delay(500.milliseconds) } } fun stop() = scope.cancel() section 15.1.2

This is deliberately different from using a regular scope for concurrent decomposition. When several children cooperate to calculate one common result, cancelling the remaining work after one failure saves resources and reflects that the result can no longer be produced. A supervisor fits independent work: one failed fetch or background task should not terminate a server process, UI component, or unrelated sibling task. section 18.2.1 section 18.2.3

Figure 18.2 When one or more child coroutines of a supervisor fail, the sibling and parent coroutines all keep on working. The exception is no longer propagated further.
CH18_F02_Isakova

Compare the failure paths visually: under supervision, a child failure leaves the parent and sibling coroutines running instead of propagating the exception through the hierarchy. section 18.2.3

A SupervisorJob remains part of structured concurrency. Cancelling its scope still cancels its children, and cancellation exceptions continue to propagate correctly. Supervision therefore isolates ordinary child failures without creating detached, unmanaged coroutines. section 18.2.3 section 15.3

Handle failures explicitly rather than treating supervision as silent recovery:

  • A direct child started with launch can report an uncaught exception to the CoroutineExceptionHandler, even while siblings continue running. section 18.2.3 section 18.3
  • A top-level async coroutine exposes its failure through Deferred; the consumer handles it by calling await() and using try-catch as needed. section 18.3.1
  • Provide a CoroutineExceptionHandler when uncaught launch failures need custom logging or reporting; it is a last-resort handler, not a replacement for local recovery. section 18.3 section 18.6

Add reporting to a supervised scope

Place SupervisorJob, a dispatcher, and a CoroutineExceptionHandler in the same context. A failing launch child is reported while the scope can continue serving other work. private val handler = CoroutineExceptionHandler { _, e -> println("[ERROR] ${e.message}") } private val scope = CoroutineScope(SupervisorJob() + dispatcher + handler) fun action() = scope.launch { throw UnsupportedOperationException("Ouch!") } section 18.3

How Kotlin in Action, 2E covers it

How deep it goes
Explains parent-child failure propagation, cancellation, exception handlers, and the launch-versus-async distinction.
Examples
Uses component-owned scopes, a heartbeat beside a failing child, and a custom CoroutineExceptionHandler.
What it assumes
Builds on coroutine scopes, contexts, and parent-child Job hierarchies while contrasting regular Job behavior.
What you can do after
Apply it via CoroutineScope to keep independent child coroutines running after a sibling fails.
How it connects
Connects CoroutineScope, Job, structured concurrency, supervisorScope, CoroutineExceptionHandler, launch, async, Deferred, and await.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.