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.
A 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
SupervisorJobchanges 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.
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
Jobwith aSupervisorJob. If any coroutine started inside thesupervisorScopefails, the other coroutines inside that same scope continue to run. - Completion: The
supervisorScopefunction does not finish until all coroutines launched inside it are complete.
| Feature | SupervisorJob | supervisorScope |
|---|---|---|
| Type | A property/object (Class instance). | A suspending function (Block of code). |
| Placement | Usually defined in the CoroutineContext. | Used inside a coroutine to wrap sub-tasks. |
| Lifecycle | Stays active until manually cancelled or the scope is destroyed. | Ends when all children inside the block finish. |
| Main Use Case | Building a long-lived scope (like viewModelScope). | Running multiple independent, temporary tasks. |
- Use
SupervisorJobwhen you are defining a global or long-lived scope where you want the scope to survive even if individual background tasks fail. - Use
supervisorScopewhen 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 tolaunch(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. UsesupervisorScope { ... }instead for local tasks.
Comments
Post a Comment