diff --git a/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala index e951760cd9..d63104f2ca 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala @@ -11,15 +11,6 @@ class HotSwapSpec extends AkkaSpec with ImplicitSender { "An Actor" must { - "be able to hotswap its behavior with HotSwap(..)" in { - val a = system.actorOf(new Actor { - def receive = { case _ ⇒ sender ! "default" } - }) - a ! HotSwap(context ⇒ { case _ ⇒ context.sender ! "swapped" }) - a ! "swapped" - expectMsg("swapped") - } - "be able to hotswap its behavior with become(..)" in { val a = system.actorOf(new Actor { def receive = { @@ -35,32 +26,6 @@ class HotSwapSpec extends AkkaSpec with ImplicitSender { expectMsg("swapped") } - "be able to revert hotswap its behavior with RevertHotSwap(..)" in { - val a = system.actorOf(new Actor { - def receive = { - case "init" ⇒ sender ! "init" - } - }) - - a ! "init" - expectMsg("init") - a ! HotSwap(context ⇒ { case "swapped" ⇒ context.sender ! "swapped" }) - - a ! "swapped" - expectMsg("swapped") - - a ! RevertHotSwap - - a ! "init" - expectMsg("init") - - // try to revert hotswap below the bottom of the stack - a ! RevertHotSwap - - a ! "init" - expectMsg("init") - } - "be able to revert hotswap its behavior with unbecome" in { val a = system.actorOf(new Actor { def receive = { diff --git a/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala index a706fd6bdb..bccf4da5c7 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala @@ -29,29 +29,6 @@ class ReceiveTimeoutSpec extends AkkaSpec { timeoutActor.stop() } - "get timeout when swapped" in { - val timeoutLatch = TestLatch() - - val timeoutActor = system.actorOf(new Actor { - context.receiveTimeout = Some(500 milliseconds) - - protected def receive = { - case ReceiveTimeout ⇒ timeoutLatch.open - } - }) - - timeoutLatch.await - - val swappedLatch = TestLatch() - - timeoutActor ! HotSwap(context ⇒ { - case ReceiveTimeout ⇒ swappedLatch.open - }) - - swappedLatch.await - timeoutActor.stop() - } - "reschedule timeout after regular receive" in { val timeoutLatch = TestLatch() case object Tick diff --git a/akka-actor-tests/src/test/scala/akka/event/LoggingReceiveSpec.scala b/akka-actor-tests/src/test/scala/akka/event/LoggingReceiveSpec.scala index 4cd1221afd..6427997b78 100644 --- a/akka-actor-tests/src/test/scala/akka/event/LoggingReceiveSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/event/LoggingReceiveSpec.scala @@ -13,7 +13,6 @@ import scala.collection.JavaConverters._ import java.util.Properties import akka.actor.Actor import akka.actor.ActorSystem -import akka.actor.HotSwap import akka.actor.UnhandledMessageException import akka.actor.PoisonPill import akka.actor.ActorSystemImpl @@ -77,22 +76,27 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd ignoreMute(this) system.eventStream.subscribe(testActor, classOf[Logging.Debug]) system.eventStream.subscribe(testActor, classOf[Logging.Error]) + + val r: Actor.Receive = { + case null ⇒ + } + val actor = TestActorRef(new Actor { - def receive = LoggingReceive(this) { - case x ⇒ - sender ! "x" + def switch: Actor.Receive = { case "becomenull" ⇒ context.become(r, false) } + def receive = switch orElse LoggingReceive(this) { + case x ⇒ sender ! "x" } }) + val name = actor.path.toString actor ! "buh" within(1 second) { expectMsg(Logging.Debug(name, "received handled message buh")) expectMsg("x") } - val r: Actor.Receive = { - case null ⇒ - } - actor ! HotSwap(_ ⇒ r, false) + + actor ! "becomenull" + EventFilter[UnhandledMessageException](pattern = "does not handle", occurrences = 1) intercept { within(500 millis) { actor ! "bah" diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 8da17f13ea..3038e3ebc3 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -30,29 +30,8 @@ sealed trait AutoReceivedMessage extends Serializable trait PossiblyHarmful -case class HotSwap(code: ActorContext ⇒ Actor.Receive, discardOld: Boolean = true) extends AutoReceivedMessage { - - /** - * Java API - */ - def this(code: akka.japi.Function[ActorContext, Procedure[Any]], discardOld: Boolean) = { - this((context: ActorContext) ⇒ { - val behavior = code(context) - val result: Actor.Receive = { case msg ⇒ behavior(msg) } - result - }, discardOld) - } - - /** - * Java API with default non-stacking behavior - */ - def this(code: akka.japi.Function[ActorContext, Procedure[Any]]) = this(code, true) -} - case class Failed(cause: Throwable) extends AutoReceivedMessage with PossiblyHarmful -case object RevertHotSwap extends AutoReceivedMessage with PossiblyHarmful - case object PoisonPill extends AutoReceivedMessage with PossiblyHarmful case object Kill extends AutoReceivedMessage with PossiblyHarmful diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index 85e008cbf6..084fc6c194 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -510,14 +510,12 @@ private[akka] final class ActorCell( if (system.settings.DebugAutoReceive) system.eventStream.publish(Debug(self.path.toString, "received AutoReceiveMessage " + msg)) msg.message match { - case HotSwap(code, discardOld) ⇒ become(code(this), discardOld) - case RevertHotSwap ⇒ unbecome() - case Failed(cause) ⇒ handleFailure(sender, cause) - case Kill ⇒ throw new ActorKilledException("Kill") - case PoisonPill ⇒ self.stop() - case SelectParent(m) ⇒ parent.tell(m, msg.sender) - case SelectChildName(name, m) ⇒ if (childrenRefs contains name) childrenRefs(name).child.tell(m, msg.sender) - case SelectChildPattern(p, m) ⇒ for (c ← children if p.matcher(c.path.name).matches) c.tell(m, msg.sender) + case Failed(cause) ⇒ handleFailure(sender, cause) + case Kill ⇒ throw new ActorKilledException("Kill") + case PoisonPill ⇒ self.stop() + case SelectParent(m) ⇒ parent.tell(m, msg.sender) + case SelectChildName(name, m) ⇒ if (childrenRefs contains name) childrenRefs(name).child.tell(m, msg.sender) + case SelectChildPattern(p, m) ⇒ for (c ← children if p.matcher(c.path.name).matches) c.tell(m, msg.sender) } } diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 4e54c58ecb..924e31ef10 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -414,10 +414,6 @@ object. throw new RuntimeException("received timeout") } -This mechanism also work for hotswapped receive functions. Every time a -``HotSwap`` is sent, the receive timeout is reset and rescheduled. - - Starting actors =============== @@ -471,19 +467,18 @@ If the sender is a ``Future`` (e.g. the message is sent with ``?``), the .. _Actor.HotSwap: -HotSwap -======= +Become/Unbecome +=============== Upgrade ------- Akka supports hotswapping the Actor’s message loop (e.g. its implementation) at -runtime. There are two ways you can do that: +runtime. -* Send a ``HotSwap`` message to the Actor. * Invoke the ``become`` method from within the Actor. -Both of these takes a ``ActorRef => PartialFunction[Any, Unit]`` that implements +Become takes a ``PartialFunction[Any, Unit]`` that implements the new message handler. The hotswapped code is kept in a Stack which can be pushed and popped. @@ -491,15 +486,7 @@ pushed and popped. Please note that the actor will revert to its original behavior when restarted by its Supervisor. -To hotswap the Actor body using the ``HotSwap`` message: - -.. code-block:: scala - - actor ! HotSwap( context => { - case message => context reply "hotswapped body" - }) - -To hotswap the Actor using ``become``: +To hotswap the Actor behavior using ``become``: .. code-block:: scala @@ -561,21 +548,14 @@ Downgrade --------- Since the hotswapped code is pushed to a Stack you can downgrade the code as -well. There are two ways you can do that: +well. -* Send the Actor a ``RevertHotswap`` message * Invoke the ``unbecome`` method from within the Actor. -Both of these will pop the Stack and replace the Actor's implementation with the +This will pop the Stack and replace the Actor's implementation with the ``PartialFunction[Any, Unit]`` that is at the top of the Stack. -Revert the Actor body using the ``RevertHotSwap`` message: - -.. code-block:: scala - - actor ! RevertHotSwap - -Revert the Actor body using the ``unbecome`` method: +Here's how you use the ``unbecome`` method: .. code-block:: scala