【问题标题】:PoisonPill causes dead letters with persistent actorPoisonPill 导致死信与持久演员
【发布时间】:2017-05-09 22:08:14
【问题描述】:

我正在使用测试套件测试持久性参与者(存储实体):

      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]

【问题讨论】:

    标签: scala akka akka-persistence


    【解决方案1】:

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

    【讨论】:

    • @jhegedus 我不认为这是正确的。在这种情况下发生的情况是接收到正常消息,然后在将其保存在 PPill 之前,actor 死亡。在您的情况下,未传递“正常”消息。我认为这是在同一发送者和接收者之间保证消息排序。在您的情况下,我的猜测是您正在从 2 个不同的匿名发件人发送消息(因为您不是从同一个 actor 发送消息,而是直接通过 tell 发送消息)。但我可能是错的。
    • 我认为 Cyrille 的回答是正确的。这是详细解释在 akka 持久性中与 PoisonPills 交互的部分:doc.akka.io/docs/akka/current/scala/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-30
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2015-08-03
    相关资源
    最近更新 更多