summaryrefslogtreecommitdiff
path: root/odcsim-engine-omega/src
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2018-11-21 23:19:32 +0100
committerFabian Mastenbroek <mail.fabianm@gmail.com>2019-05-13 20:26:45 +0200
commitff49cd6c9079264e04d2efa85b03a024d0e00cca (patch)
treebc925038f730e784c7d8ed3c0cbe0e07178b0417 /odcsim-engine-omega/src
parente1530fee893b5e9ceebf5e07b490c1c82da2e687 (diff)
feat: Add consistent exception handling in actor systems
This change makes exception handling in actor systems consistent. Implementors should not propagate unhandled exceptions in actors to the (one of the) threads running the engine, but instead should stop the offending actor and continue running. Supervision of actors should be implemented within actor behavior instead. Since BehaviorInterpreter will propagate exceptions thrown by an actor, consumers of that API can use it to catch unhandled exceptions in an actor.
Diffstat (limited to 'odcsim-engine-omega/src')
-rw-r--r--odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt20
1 files changed, 17 insertions, 3 deletions
diff --git a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt
index 56e3020f..c4a9b35f 100644
--- a/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt
+++ b/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaActorSystem.kt
@@ -35,6 +35,7 @@ import com.atlarge.odcsim.PostStop
import com.atlarge.odcsim.PreStart
import com.atlarge.odcsim.Signal
import com.atlarge.odcsim.internal.BehaviorInterpreter
+import mu.KotlinLogging
import java.util.PriorityQueue
import kotlin.math.max
@@ -75,6 +76,11 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String)
*/
private val registry: MutableMap<ActorPath, Actor<*>> = HashMap()
+ /**
+ * A [KotlinLogging] instance that writes logs to a SLF4J implementation.
+ */
+ private val logger = KotlinLogging.logger {}
+
init {
registry[path] = Actor(this, root)
schedule(this, PreStart, .0)
@@ -100,8 +106,16 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String)
time = delivery
queue.poll()
- // Notice that messages for unknown/terminated actors are ignored for now
- registry[envelope.destination]?.interpretMessage(envelope.message)
+ val actor = registry[envelope.destination] ?: continue
+ try {
+ // Notice that messages for unknown/terminated actors are ignored for now
+ actor.interpretMessage(envelope.message)
+ } catch (e: Exception) {
+ // Forcefully stop the actor if it crashed
+ actor.stop()
+
+ logger.error(e) { "Unhandled exception in actor ${envelope.destination}" }
+ }
}
// Jump forward in time as the caller expects the system to have run until the specified instant
@@ -171,7 +185,7 @@ class OmegaActorSystem<in T : Any>(root: Behavior<T>, override val name: String)
* Terminate this actor and its children.
*/
fun terminate() {
- children.forEach { it.terminate() }
+ children.forEach { it.stop() }
registry.remove(self.path)
}