SupervisorScope vs. SupervisorJob

 While both are used to handle Structured Concurrency and prevent a single failure from crashing an entire system, they are applied at different levels of the coroutine hierarchy.

1. SupervisorJob

SupervisorJob is a specific type of Job that you can pass into a CoroutineScope or a coroutine context.

  • Failure Propagation: Normally, if a child coroutine fails, it cancels its parent and all its siblings. A SupervisorJob changes this: a failure of a child does not result in the cancellation of the parent or other siblings.
  • Usage: It is typically used when creating a custom scope (e.g., a background service that manages multiple independent tasks).
  • Key Detail: You must handle exceptions manually (usually via a CoroutineExceptionHandler), or the exception will still reach the thread's uncaught exception handler.

2. SupervisorScope

supervisorScope is a suspending function that creates a new sub-scope with a SupervisorJob.

  • Scope Level: It is used inside an existing coroutine to wrap a block of work.
  • Behavior: It inherits the context from the outer scope but overrides the Job with a SupervisorJob. If any coroutine started inside the supervisorScope fails, the other coroutines inside that same scope continue to run.
  • Completion: The supervisorScope function does not finish until all coroutines launched inside it are complete.

Key Differences

FeatureSupervisorJobsupervisorScope
TypeA property/object (Class instance).A suspending function (Block of code).
PlacementUsually defined in the CoroutineContext.Used inside a coroutine to wrap sub-tasks.
LifecycleStays active until manually cancelled or the scope is destroyed.Ends when all children inside the block finish.
Main Use CaseBuilding a long-lived scope (like viewModelScope).Running multiple independent, temporary tasks.

When to use which?

  • Use SupervisorJob when you are defining a global or long-lived scope where you want the scope to survive even if individual background tasks fail.
  • Use supervisorScope when you have a specific function that needs to run several concurrent tasks, and you don't want one failing task to stop the others in that specific group.

Crucial Warning: If you pass a SupervisorJob() as an argument to launch(SupervisorJob()), it becomes the parent of that coroutine, but it is not linked to the outer scope. This often leads to memory leaks because the new coroutine is no longer a child of the original scope. Use supervisorScope { ... } instead for local tasks.

Comments

Popular posts from this blog

What is a Coroutine? Why is it better than threads?

What are Coroutine Builders?

Sealed Classes and Sealed Interfaces