From ff49cd6c9079264e04d2efa85b03a024d0e00cca Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 21 Nov 2018 23:19:32 +0100 Subject: 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. --- odcsim-engine-omega/build.gradle | 2 ++ .../atlarge/odcsim/engine/omega/OmegaActorSystem.kt | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'odcsim-engine-omega') diff --git a/odcsim-engine-omega/build.gradle b/odcsim-engine-omega/build.gradle index b8399a4e..f60dbe89 100644 --- a/odcsim-engine-omega/build.gradle +++ b/odcsim-engine-omega/build.gradle @@ -35,9 +35,11 @@ dependencies { api project(':odcsim-core') implementation "org.jetbrains.kotlin:kotlin-stdlib" + implementation "io.github.microutils:kotlin-logging:1.6.20" testCompile project(path: ':odcsim-core', configuration: 'tests') testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_jupiter_version" testImplementation "org.junit.platform:junit-platform-launcher:$junit_platform_version" + testRuntimeOnly "org.slf4j:slf4j-simple:1.7.25" } 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(root: Behavior, override val name: String) */ private val registry: MutableMap> = 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(root: Behavior, 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(root: Behavior, override val name: String) * Terminate this actor and its children. */ fun terminate() { - children.forEach { it.terminate() } + children.forEach { it.stop() } registry.remove(self.path) } -- cgit v1.2.3