我正在使用测试工具包测试持久性actor(存储实体):
val testActor = system.actorOf((IMPersistentActor.props("id1")))
testActor ! AddElementCommand(refVal)
// expectMsg(AddElementResponse(Success(refVal))) // no dead letters if I uncomment this
testActor ! PoisonPill
给出:
Message [app.server.persistence.IMPersistentActor$AddElementCommand]
from Actor[akka://IMPersistentActorTest/system/testActor-1#182376248]
to Actor[akka://IMPersistentActorTest/user/$a#-899768724] was not delivered.
我认为AddElementCommand(refVal)
应该在PoisonPill
之前到达并且应该被处理。如何解释这种行为?为什么我会收到这封死信呢?
然而有趣的是,如果我取消注释expectMsg(AddElementResponse(Success(refVal)))
,那么我没有死信并且测试通过了。那是为什么?
以下是完整代码:
class IMPersistentActorTest
extends TestKit(ActorSystem("IMPersistentActorTest"))
with WordSpecLike
with Matchers
with BeforeAndAfterAll
with ImplicitSender {
override
def afterAll: Unit = {
TestKit.shutdownActorSystem(system)
}
"Actor" should {
val el = Line(title = Some("bla"))
val refVal: RefVal[Line] = RefVal.makeWithNewUUID[Line](el)
"add an item to the list and preserve it after restart" in {
// val testActor = system.actorOf(Props(new IMPersistentActor("sc-000001") with RestartableActor))
val testActor = system.actorOf((IMPersistentActor.props("id1")))
testActor ! AddElementCommand(refVal)
val state: State = IMPersistentActor.addEntity(IMPersistentActor.initState, refVal)
testActor ! PoisonPill
val testActor2: ActorRef = system.actorOf((IMPersistentActor.props("id1")))
testActor2 ! GetElementsRequest
expectMsg(GetElementsResponse(state))
}
}
}
class IMPersistentActor(id: String) extends PersistentActor with ActorLogging {
private var state: State =initState
override def persistenceId: String = id
override def receiveCommand: Receive = {
case AddElementCommand(item) =>
persist(EntityAdded(item)) { evt =>
state = applyEvent(evt)
sender() ! AddElementResponse(Success(item))
}
case GetElementsRequest => sender() ! GetElementsResponse(state)
}
override def receiveRecover: Receive = {
case evt: Event => state = applyEvent(evt)
case RecoveryCompleted => log.info("Recovery completed!")
}
private def applyEvent(event: Event): State = event match {
case EntityAdded(refVal: (RefValDyn)) => addEntity(state, refVal)
}
}
object IMPersistentActor {
type State = Map[RefDyn, RefValDyn]
def initState:State=Map.empty
def addEntity(s: State, refVal: RefValDyn): State = s + (refVal.r -> refVal)
def props(id: String): Props = Props(new IMPersistentActor(id))
// protocol
case class AddElementCommand(entity: RefValDyn)
case class AddElementResponse(entity: Try[RefValDyn])
case object GetElementsRequest
case class GetElementsResponse(items: State)
// events
sealed trait Event
case class EntityAdded(entity: RefValDyn) extends Event
}
trait IMPersistentActorComm[T]