Merge pull request #138 from jboner/wip-reset_behaviors_on_restart
#1429 - reverting hotswap on restart and termination
This commit is contained in:
commit
bf3ce9bb87
3 changed files with 50 additions and 79 deletions
|
|
@ -7,144 +7,109 @@ package akka.actor
|
|||
import akka.testkit._
|
||||
|
||||
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
||||
class HotSwapSpec extends AkkaSpec {
|
||||
class HotSwapSpec extends AkkaSpec with ImplicitSender {
|
||||
|
||||
"An Actor" must {
|
||||
|
||||
"be able to hotswap its behavior with HotSwap(..)" in {
|
||||
val barrier = TestBarrier(2)
|
||||
@volatile
|
||||
var _log = ""
|
||||
val a = system.actorOf(new Actor {
|
||||
def receive = { case _ ⇒ _log += "default" }
|
||||
})
|
||||
a ! HotSwap(context ⇒ {
|
||||
case _ ⇒
|
||||
_log += "swapped"
|
||||
barrier.await
|
||||
def receive = { case _ ⇒ sender ! "default" }
|
||||
})
|
||||
a ! HotSwap(context ⇒ { case _ ⇒ context.sender ! "swapped" })
|
||||
a ! "swapped"
|
||||
barrier.await
|
||||
_log must be("swapped")
|
||||
expectMsg("swapped")
|
||||
}
|
||||
|
||||
"be able to hotswap its behavior with become(..)" in {
|
||||
val barrier = TestBarrier(2)
|
||||
@volatile
|
||||
var _log = ""
|
||||
val a = system.actorOf(new Actor {
|
||||
def receive = {
|
||||
case "init" ⇒
|
||||
_log += "init"
|
||||
barrier.await
|
||||
case "swap" ⇒ context.become({
|
||||
case _ ⇒
|
||||
_log += "swapped"
|
||||
barrier.await
|
||||
})
|
||||
case "init" ⇒ sender ! "init"
|
||||
case "swap" ⇒ context.become({ case x: String ⇒ context.sender ! x })
|
||||
}
|
||||
})
|
||||
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
expectMsg("init")
|
||||
a ! "swap"
|
||||
a ! "swapped"
|
||||
barrier.await
|
||||
_log must be("swapped")
|
||||
expectMsg("swapped")
|
||||
}
|
||||
|
||||
"be able to revert hotswap its behavior with RevertHotSwap(..)" in {
|
||||
val barrier = TestBarrier(2)
|
||||
@volatile
|
||||
var _log = ""
|
||||
val a = system.actorOf(new Actor {
|
||||
def receive = {
|
||||
case "init" ⇒
|
||||
_log += "init"
|
||||
barrier.await
|
||||
case "init" ⇒ sender ! "init"
|
||||
}
|
||||
})
|
||||
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
a ! HotSwap(context ⇒ {
|
||||
case "swapped" ⇒
|
||||
_log += "swapped"
|
||||
barrier.await
|
||||
})
|
||||
expectMsg("init")
|
||||
a ! HotSwap(context ⇒ { case "swapped" ⇒ context.sender ! "swapped" })
|
||||
|
||||
a ! "swapped"
|
||||
barrier.await
|
||||
_log must be("swapped")
|
||||
expectMsg("swapped")
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
a ! RevertHotSwap
|
||||
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
expectMsg("init")
|
||||
|
||||
// try to revert hotswap below the bottom of the stack
|
||||
barrier.reset
|
||||
_log = ""
|
||||
a ! RevertHotSwap
|
||||
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
expectMsg("init")
|
||||
}
|
||||
|
||||
"be able to revert hotswap its behavior with unbecome" in {
|
||||
val barrier = TestBarrier(2)
|
||||
@volatile
|
||||
var _log = ""
|
||||
val a = system.actorOf(new Actor {
|
||||
def receive = {
|
||||
case "init" ⇒
|
||||
_log += "init"
|
||||
barrier.await
|
||||
case "init" ⇒ sender ! "init"
|
||||
case "swap" ⇒
|
||||
context.become({
|
||||
case "swapped" ⇒
|
||||
_log += "swapped"
|
||||
barrier.await
|
||||
sender ! "swapped"
|
||||
case "revert" ⇒
|
||||
context.unbecome()
|
||||
})
|
||||
barrier.await
|
||||
}
|
||||
})
|
||||
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
expectMsg("init")
|
||||
a ! "swap"
|
||||
barrier.await
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
a ! "swapped"
|
||||
barrier.await
|
||||
_log must be("swapped")
|
||||
expectMsg("swapped")
|
||||
|
||||
barrier.reset
|
||||
_log = ""
|
||||
a ! "revert"
|
||||
a ! "init"
|
||||
barrier.await
|
||||
_log must be("init")
|
||||
expectMsg("init")
|
||||
}
|
||||
|
||||
"revert to initial state on restart" in {
|
||||
|
||||
val a = system.actorOf(new Actor {
|
||||
def receive = {
|
||||
case "state" ⇒ sender ! "0"
|
||||
case "swap" ⇒
|
||||
context.become({
|
||||
case "state" ⇒ sender ! "1"
|
||||
case "swapped" ⇒ sender ! "swapped"
|
||||
case "crash" ⇒ throw new Exception("Crash (expected)!")
|
||||
})
|
||||
sender ! "swapped"
|
||||
}
|
||||
})
|
||||
a ! "state"
|
||||
expectMsg("0")
|
||||
a ! "swap"
|
||||
expectMsg("swapped")
|
||||
a ! "state"
|
||||
expectMsg("1")
|
||||
EventFilter[Exception](message = "Crash (expected)!", occurrences = 1) intercept { a ! "crash" }
|
||||
a ! "state"
|
||||
expectMsg("0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ private[akka] final class ActorCell(
|
|||
}
|
||||
}
|
||||
actor = freshActor // assign it here so if preStart fails, we can null out the sef-refs next call
|
||||
hotswap = Props.noHotSwap // Reset the behavior
|
||||
freshActor.postRestart(cause)
|
||||
if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, "restarted"))
|
||||
|
||||
|
|
@ -534,6 +535,7 @@ private[akka] final class ActorCell(
|
|||
} finally {
|
||||
currentMessage = null
|
||||
clearActorFields()
|
||||
hotswap = Props.noHotSwap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -487,6 +487,10 @@ Both of these takes a ``ActorRef => PartialFunction[Any, Unit]`` that implements
|
|||
the new message handler. The hotswapped code is kept in a Stack which can be
|
||||
pushed and popped.
|
||||
|
||||
.. warning::
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue