PoisonPill会导致持久演员死信

时间:2017-05-09 22:08:14

标签: scala akka akka-persistence

我正在使用测试工具包测试持久性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]

1 个答案:

答案 0 :(得分:2)

您应该查看文档的this part。简短版本是持久性是异步处理的,因此在消息告诉参与者该事件已被持久化之前收到PoisonPill消息。