Invoke exception handler for actor on cancellation even when channel was successfully closed, so exceptions thrown by actor are always reported
Fixes #368
diff --git a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Actor.kt b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Actor.kt
index 54adc81..f128d9e 100644
--- a/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Actor.kt
+++ b/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/channels/Actor.kt
@@ -163,8 +163,9 @@
active: Boolean
) : ChannelCoroutine<E>(parentContext, channel, active), ActorScope<E>, ActorJob<E> {
override fun onCancellation(cause: Throwable?) {
- if (!_channel.cancel(cause) && cause != null)
- handleCoroutineException(context, cause)
+ _channel.cancel(cause)
+ // Always propagate the exception, don't wait for actor senders
+ if (cause != null) handleCoroutineException(context, cause)
}
}
@@ -178,7 +179,7 @@
block.startCoroutineCancellable(this, this)
}
- suspend override fun send(element: E) {
+ override suspend fun send(element: E) {
start()
return super.send(element)
}
@@ -197,4 +198,3 @@
super.onSend.registerSelectClause2(select, param, block)
}
}
-
diff --git a/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ActorTest.kt b/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ActorTest.kt
index 5109ba6..e789f4d 100644
--- a/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ActorTest.kt
+++ b/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/channels/ActorTest.kt
@@ -146,4 +146,20 @@
finish(3)
}
+
+ @Test
+ fun testThrowingActor() = runTest(unhandled = listOf({e -> e is IllegalArgumentException})) {
+ val parent = Job()
+ val actor = actor<Int>(context = coroutineContext, parent = parent) {
+ channel.consumeEach {
+ expect(1)
+ throw IllegalArgumentException()
+ }
+ }
+
+ actor.send(1)
+ parent.cancel()
+ parent.join()
+ finish(2)
+ }
}