From 2f6dcaef25d80a1411512e482953c83990149fd1 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 9 May 2019 17:54:02 +0200 Subject: refactor: Make actor spawning and stopping behavior consistent This change makes the behavior for spawning and stopping a child actor more consistent and better specified in the documentation. --- .../main/kotlin/com/atlarge/odcsim/ActorContext.kt | 26 +++++++++++++++++++--- .../main/kotlin/com/atlarge/odcsim/ActorPath.kt | 5 +++++ .../main/kotlin/com/atlarge/odcsim/ActorSystem.kt | 13 ++++++++--- .../src/main/kotlin/com/atlarge/odcsim/Signals.kt | 17 +++++++------- .../com/atlarge/odcsim/internal/Coroutines.kt | 7 +++++- 5 files changed, 53 insertions(+), 15 deletions(-) (limited to 'odcsim-core/src/main') diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt index 499e7df0..f8128490 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorContext.kt @@ -37,6 +37,11 @@ interface ActorContext { */ val self: ActorRef + /** + * A view of the children of this actor. + */ + val children: List> + /** * The point of time within the simulation. */ @@ -52,6 +57,14 @@ interface ActorContext { */ val log: Logger + /** + * Obtain the child of this actor with the specified name. + * + * @param name The name of the child actor to obtain. + * @return The reference to the child actor or `null` if it does not exist. + */ + fun getChild(name: String): ActorRef<*>? + /** * Send the specified message to the actor referenced by this [ActorRef]. * @@ -69,6 +82,9 @@ interface ActorContext { /** * Spawn a child actor from the given [Behavior] and with the specified name. * + * The name may not be empty or start with "$". Moreover, the name of an actor must be unique and this method + * will throw an [IllegalArgumentException] in case a child actor of the given name already exists. + * * @param behavior The behavior of the child actor to spawn. * @param name The name of the child actor to spawn. * @return A reference to the child that has/will be spawned. @@ -84,12 +100,16 @@ interface ActorContext { fun spawnAnonymous(behavior: Behavior): ActorRef /** - * Request the specified child actor to be stopped in asynchronous fashion. + * Force the specified child actor to terminate after it finishes processing its current message. + * Nothing will happen if the child is already stopped. + * + * Only direct children of an actor may be stopped through the actor context. Trying to stop other actors via this + * method will result in an [IllegalArgumentException]. Instead, stopping other actors has to be expressed as + * an explicit stop message that the actor accept. * * @param child The reference to the child actor to stop. - * @return `true` if the ref points to a child actor, otherwise `false`. */ - fun stop(child: ActorRef<*>): Boolean + fun stop(child: ActorRef<*>) /** * Watch the specified [ActorRef] for termination of the referenced actor. On termination of the watched actor, diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt index f51a4fed..a6c716a2 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorPath.kt @@ -50,6 +50,11 @@ sealed class ActorPath : Comparable, Serializable { */ fun child(name: String): ActorPath = Child(this, name) + /** + * Create a new child actor path. + */ + operator fun div(name: String): ActorPath = child(name) + /** * Recursively create a descendant’s path by appending all child names. */ diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt index bae1fb74..d65beebd 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/ActorSystem.kt @@ -59,11 +59,18 @@ interface ActorSystem : ActorRef { fun send(msg: T, after: Duration = 0.1) /** - * Terminates this actor system. + * Terminates this actor system in an asynchronous fashion. * * This will stop the root actor and in turn will recursively stop all its child actors. - * - * This is an asynchronous operation. */ fun terminate() + + /** + * Create an actor in the "/system" namespace. This actor will be shut down during `system.terminate()` only after + * all user actors have terminated. + * + * @param behavior The behavior of the system actor to spawn. + * @param name The name of the system actor to spawn. + */ + suspend fun spawnSystem(behavior: Behavior, name: String): ActorRef } diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt index 2ad042e3..9b707348 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/Signals.kt @@ -37,9 +37,18 @@ object PreStart : Signal /** * Lifecycle signal that is fired after this actor and all its child actors (transitively) have terminated. + * The [Terminated] signal is only sent to registered watchers after this signal has been processed. */ object PostStop : Signal +/** + * A lifecycle signal to indicate that an actor that was watched has terminated. + * + * @property ref The reference to the actor that has terminated. + * @property failure The failure that caused the termination, or `null` on graceful termination. + */ +data class Terminated(val ref: ActorRef<*>, val failure: Throwable? = null) : Signal + /** * A [Signal] to indicate an actor has timed out. * @@ -49,11 +58,3 @@ object PostStop : Signal * @property target The target object that has timed out. */ data class Timeout(val target: Any) : Signal - -/** - * A lifecycle signal to indicate that an actor that was watched has terminated. - * - * @property ref The reference to the actor that has terminated. - * @property failure The failure that caused the termination, or `null` on graceful termination. - */ -data class Terminated(val ref: ActorRef<*>, val failure: Throwable? = null) : Signal diff --git a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt index 13e722fc..f9e8de00 100644 --- a/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt +++ b/odcsim-core/src/main/kotlin/com/atlarge/odcsim/internal/Coroutines.kt @@ -95,19 +95,24 @@ internal class SuspendingBehaviorImpl( override val time: Instant get() = actorContext.time + override val children: List> + get() = actorContext.children + override val system: ActorSystem<*> get() = actorContext.system override val log: Logger get() = actorContext.log + override fun getChild(name: String): ActorRef<*>? = actorContext.getChild(name) + override fun send(ref: ActorRef, msg: U, after: Duration) = actorContext.send(ref, msg, after) override fun spawn(behavior: Behavior, name: String) = actorContext.spawn(behavior, name) override fun spawnAnonymous(behavior: Behavior) = actorContext.spawnAnonymous(behavior) - override fun stop(child: ActorRef<*>): Boolean = actorContext.stop(child) + override fun stop(child: ActorRef<*>) = actorContext.stop(child) override fun watch(target: ActorRef<*>) = actorContext.watch(target) -- cgit v1.2.3