Skip to content

deferred.await() with try-catch inside a launch{} is cancelling all coroutines in a scope when exception occur. #2147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
premkumarroyal opened this issue Jul 17, 2020 · 3 comments
Labels

Comments

@premkumarroyal
Copy link

premkumarroyal commented Jul 17, 2020

Hi,
I am launching multiple coroutines using async, directly in scope, and calling .await() in another coroutine with launch builder.

All async are in scope level so calling await will throw an exception, so I wrapped deferred.await() with try-catch and expected that it should not cancel all other coroutines that are running.

But all coroutines are canceled. Please find the code.

private fun multipleCoroutinesAtScopeLevel() {

    val scope = CoroutineScope(CoroutineName("ParentJob"))

    val firstDef = scope.async(CoroutineName("firstDef")) {
      delay(2000)
      throw IllegalAccessException();
      return@async "First"
    }
    val secondDef = scope.async(CoroutineName("secondDef")) {
      delay(4000)
      return@async "Second"
    }
    val thirdDeff = scope.async(CoroutineName("thirdDeff")) {
      delay(3000)
      return@async "third"
    }

    val helperJob = scope.launch(CoroutineName("HelperJob")) {
      try {
        firstDef.await()
      } catch (e: Exception) {
        Log.e(TAG, "Exception at $firstDef")
      }

      secondDef.await()
      thirdDeff.await()
    }
  }

Output:
"secondDef#2":DeferredCoroutine{Cancelled}@9a4604f
"thirdDeff#3":DeferredCoroutine{Cancelled}@c6f43dc
Exception at "firstDef#1":DeferredCoroutine{Cancelling}@a351ce5
"HelperJob#4":StandaloneCoroutine{Cancelled}@58943ba

If this is as expected, may I know a little more about it?

@dalvin
Copy link

dalvin commented Jul 19, 2020

I tried wrapping this in runBlocking and runBlockingTest

runBlockingTest is working fine and providing secondDeff and thirdDeff values successfully.

Should there be a difference in structured concurrency behavior between runBlocking and runBlockingTest?

@elizarov
Copy link
Contributor

This is so by design. Please, consult a section of the guide on the structured concurrency: https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html#structured-concurrency-with-async
Does it help?

@premkumarroyal
Copy link
Author

premkumarroyal commented Jul 20, 2020

Thanks @elizarov

Understand. I think it would be better if we have detailed docs on exception handling in a nested coroutine and exception propagation to parent. It took quite some time to me understand after trying out some samples and reading some blogs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants