Daniel Asher
12/10/2019, 5:37 AMSupervisorJob
and to launch
a new coroutine for every transition so as not to have parent coroutines cancelled, but when I’m calling the API, I can’t quite figure out how to get the exception back to the client. Here’s some code, apologies for any conceptual errors on my part:
class CoroutineExceptionTest: BehaviorSpec() {
val supervisorJob = SupervisorJob()
val coroutineScope: CoroutineScope = CoroutineScope(newSingleThreadContext("serviceContext") + supervisorJob)
class InvalidEventException(override val message: String): Exception(message)
fun tryTransition(state: Int, event: Int): Int {
return when (event >= state) {
true -> event + state
false -> throw InvalidEventException("Argument $event is invalid")
}
}
val stateChannel = ConflatedBroadcastChannel(0)
val currentState: Int get() = stateChannel.value
var eventChannel = coroutineScope.actor<Int>() {
for (event in channel) {
if (coroutineScope.isActive) {
launch {
val newState = tryTransition(currentState, event)
stateChannel.send(newState)
}
}
}
}
suspend fun add(number: Int): Int { // HOW DO I GET EXCEPTION THROWN HERE?
eventChannel.send(number)
return stateChannel.value
}
init {
Given("we are in initial state") {
currentState shouldBe 0
When("adding 2") {
add(2)
Then("the state should be 2") {
currentState shouldBe 2
}
}
When("trying to add 1") {
Then("we should get an invalid event exception") {
val exception = shouldThrow<InvalidEventException> {
add(1) // THIS IS MY PROBLEM: java.lang.AssertionError: Expected exception CoroutineExceptionTest.InvalidEventException but no exception was thrown.
}
}
}
}
}
}
Daniel Asher
12/10/2019, 9:12 AMChannel
supported a next* (error | completed)
grammar, but it looks like the grammar is next* completed
so error propagation is handled manually. I’ll take a look at Flow
. The reason I chose Channel
and ConflatedBroadcastChannel
was I was trying to replicate BehaviorSubject
from the Rx
world.