coroutineScope vs supervisorScope

Authors
coroutineScope vs supervisorScope

A coroutineScope cancels all its children whenever any one of its children fails, whereas a supervisorScope does not cancel the other children when one of them fails.

In this blog, we will learn about the coroutineScope vs supervisorScope of Kotlin Coroutines.

I am Amit Shekhar, Founder @ Outcome School, I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.

I teach AI and Machine Learning, and Android at Outcome School.

Join Outcome School and get a high-paying tech job:

Let's get started.

There is a major difference between the coroutineScope and the supervisorScope, and we must understand that difference otherwise we will make mistakes without knowing what is happening with the Kotlin Coroutines code.

As always, I am taking a real example use-case to understand this major difference between the coroutineScope and the supervisorScope.

Example use case:

Suppose, we have two network calls as follows:

  • getUsers()
  • getMoreUsers()

We want to make these two network calls in parallel to get the data from the server.

You can find the complete source code of this example on this GitHub repository: Learn Kotlin Coroutines

In Kotlin Coroutines, for doing tasks in parallel.

launch {
    try {
        coroutineScope {
            val usersDeferred = async {  getUsers() }
            val moreUsersDeferred = async { getMoreUsers() }
            val users = usersDeferred.await()
            val moreUsers = moreUsersDeferred.await()
        }
    } catch (exception: Exception) {
        // handle exception
    }
}

Now, if any network error comes, it will go to the catch block. We have used the coroutineScope.

But suppose again, we want to return an empty list for the network call which has failed and continue with the response from the other network call. We will have to use the supervisorScope and add the try-catch block to the individual network call as below:

launch {
    supervisorScope {
        val usersDeferred = async { getUsers() }
        val moreUsersDeferred = async { getMoreUsers() }
        val users = try {
            usersDeferred.await()
        } catch (e: Exception) {
            emptyList<User>()
        }
        val moreUsers = try {
            moreUsersDeferred.await()
        } catch (e: Exception) {
            emptyList<User>()
        }
    }
}

So now, if any error comes, it will continue with the empty list. This is how supervisorScope helps.

A quick note for you

No matter which tech domain you work in, get familiar with these topics:

  • LLM
  • RAG
  • MCP
  • Agent
  • Fine-tuning
  • Quantization

We put it all together in one video:

AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization

No need to stop reading - bookmark it and watch later when you get time. Future you will thank you.

Now, let's get back to the topic.

The major difference:

  • A coroutineScope will cancel whenever any of its children fail.
  • A supervisorScope won't cancel other children when one of them fails.

Note:

  • Use coroutineScope with the top-level try-catch, when you do NOT want to continue with other tasks if any of them have failed.
  • If we want to continue with the other tasks even when one fails, we go with the supervisorScope.
  • Use supervisorScope with the individual try-catch for each task, when you want to continue with other tasks if one or some of them have failed.

This was all about the coroutineScope and the supervisorScope that are present in the Kotlin Coroutines.

To master coroutineScope, supervisorScope, structured concurrency, and exception handling hands-on along with the rest of the Android stack, check out the Android Program by Outcome School.

Stay updated: Subscribe to our newsletter to get our latest AI and Machine Learning blogs straight to your inbox.

Frequently Asked Questions

Does one failing child cancel the others in supervisorScope?

No. A supervisorScope won't cancel other children when one of them fails. A coroutineScope, on the other hand, will cancel whenever any of its children fail.

Where should we put the try-catch with coroutineScope?

We should put a top-level try-catch around the coroutineScope. This fits when we do not want to continue with other tasks if any of them have failed. Any network error from the parallel calls then goes to that single catch block.

How can we continue with other network calls when one of them fails?

We use supervisorScope and add a try-catch to each individual await() call. In the catch block, we return a fallback like an empty list. This way, the failed call gives an empty list, and we continue with the response from the other call.

That's it for now.

Thanks

Amit Shekhar
Founder @ Outcome School

You can connect with me on:

Follow Outcome School on:

Read all of our high-quality blogs here.