Skip to content

Some codes won't be executed after throwing an exception #686

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
Tea-Ayataka opened this issue Oct 9, 2018 · 6 comments
Closed

Some codes won't be executed after throwing an exception #686

Tea-Ayataka opened this issue Oct 9, 2018 · 6 comments

Comments

@Tea-Ayataka
Copy link

Code:

import kotlinx.coroutines.experimental.*

fun main(args: Array<String>) {
    val job = Job()
    val context = Dispatchers.Default + job
    val scope = CoroutineScope(context)

    runBlocking {
        scope.launch { say("first") }
        delay(1000)
        scope.launch { say("second") }
        delay(1000)
    }
}

fun say(text: String) {
    println("Hello World")
    throw IllegalArgumentException(text)
}

Result:

Hello World
Exception in thread "DefaultDispatcher-worker-2" java.lang.IllegalArgumentException: first
	at test.kotlin.CoroutineTestKt.say(CoroutineTest.kt:20)
	at test.kotlin.CoroutineTestKt$main$1$1.doResume(CoroutineTest.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:42)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:168)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:13)
	at kotlinx.coroutines.experimental.scheduling.Task.run(Tasks.kt:94)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:732)
Exception in thread "DefaultDispatcher-worker-2" java.lang.IllegalArgumentException: first
	at test.kotlin.CoroutineTestKt.say(CoroutineTest.kt:20)
	at test.kotlin.CoroutineTestKt$main$1$1.doResume(CoroutineTest.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:42)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:168)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:13)
	at kotlinx.coroutines.experimental.scheduling.Task.run(Tasks.kt:94)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:732)

So, I have no idea wtf is going on.

Kotlin 1.2.71
Coroutine 0.30.2
Java 1.8.0_181

@qwwdfsad
Copy link
Member

qwwdfsad commented Oct 9, 2018

Please clarify what behaviour are you expecting here?

@Tea-Ayataka
Copy link
Author

If i execute multiple launch or async with the same coroutine scope and an exception is thrown from one of them, The program stops working correctly.
This won't happen if i use GlobalScope instead.

@Tea-Ayataka
Copy link
Author

I was excepting the following result.

Hello World
Exception in thread "DefaultDispatcher-worker-1" java.lang.IllegalArgumentException: first
	at test.kotlin.CoroutineTestKt.say(CoroutineTest.kt:20)
	at test.kotlin.CoroutineTestKt$main$1$1.doResume(CoroutineTest.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:42)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:168)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:13)
	at kotlinx.coroutines.experimental.scheduling.Task.run(Tasks.kt:94)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:732)
Hello World
Exception in thread "DefaultDispatcher-worker-1" java.lang.IllegalArgumentException: second
	at test.kotlin.CoroutineTestKt.say(CoroutineTest.kt:20)
	at test.kotlin.CoroutineTestKt$main$1$2.doResume(CoroutineTest.kt:13)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:42)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:168)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:13)
	at kotlinx.coroutines.experimental.scheduling.Task.run(Tasks.kt:94)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
	at kotlinx.coroutines.experimental.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:732)

@qwwdfsad
Copy link
Member

qwwdfsad commented Oct 9, 2018

The current behaviour is expected.
What happens:

  1. scope.launch { say("first") } executes, fails with an exception and fails its parent (which is plain Job you put in the scope)
  2. When line with scope.launch { say("second") } is executing, parent job is already cancelled and thus this launch is not even started and became immediately failed.

You have two options to have a desired behaviour:

  1. Replace Job with SupervisorJob. SupervisorJob is not cancelled on child failure, but it cancels children when svJob.cancel() is invoked
  2. Use launch(start = CoroutineStart.ATOMIC). Then coroutine will be launched anyway (but in "failing" state) and fail on first cancellable suspensin point

@qwwdfsad qwwdfsad closed this as completed Oct 9, 2018
@hrach
Copy link
Contributor

hrach commented Oct 9, 2018

@qwwdfsad

is not even started and became immediately failed.

I get this. But I do not expect the result of this should result in

Exception in thread "DefaultDispatcher-worker-2" java.lang.IllegalArgumentException: first

but some other exception that will tell me that the parent job is in failed state.

@qwwdfsad
Copy link
Member

qwwdfsad commented Oct 9, 2018

Yes, this is slightly counter-intuitive.

But consider following code:

val job = Job()
CoroutineScope(job).launch {delay(Long.MAX_VALUE) }
job.cancel(IllegalArgumentException())

Do you expect to IllegalArgumentException to be printed? Presumably yes.

Now assume there is a race between lines 2 and 3 (or just swap these lines). Should behaviour be different in that case? The current answer is "no", though we can consider reworking this part

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

No branches or pull requests

3 participants