使用 ActorSelection 识别 Actor

Identifying an Actor using an ActorSelection

我正在写一个 Actor 应该看另一个 Actor;我们将后者称为 target。一旦目标停止,我的 Actor 就会自行停止。对于这个目标,我只有一个 ActorSelection。要观看它,我显然需要一个 ActorRef,所以我想我应该向 ActorSelection 发送一个 Identify 消息;当它回复 ActorIdentity 时,我会得到它的 ActorRef。到目前为止一切顺利,但我无法让它工作。

规格如下:

// Arrange
val probe = TestProbe()
val target = TestProbe().ref
val sut = system.actorOf(MyActor.props(system.actorSelection(target.path)), "watch-target")
probe watch sut

// Act
target ! PoisonPill

// Assert
probe.expectTerminated(sut)

和实现(FSM,细节略过):

log.debug("Asking target selection {} to identify itself; messageId={}", selection.toString(), messageId)
selection ! Identify(messageId)

when(Waiting) {
  case Event(ActorIdentity(`messageId`, Some(ref)), Queue(q)) =>
    log.info("Received identity for remote target: {}", ref)
    context.watch(ref)
    goto(NextState) using TargetFound(ref)
  case Event(ActorIdentity(`messageId`, None), Queue(q)) =>
    log.error("Could not find requested target {}", selection.toString())
    stop()
}

initialize()

现在,当我运行 我的测试时,它是绿色的,因为被测系统确实停止了。但问题是它会自行停止,因为它无法使用上述步骤找到目标。日志文件显示:

Asking target selection ActorSelection[Anchor(akka://default/), Path(/system/testProbe-3)] to identify itself; messageId=871823258

Could not find requested target ActorSelection[Anchor(akka://default/), Path(/system/testProbe-3)]

我是不是遗漏了什么明显的东西?也许 TestProbe 不应该暴露它的真实身份?我什至尝试将虚拟 Actor 实例化为 target 但结果是一样的。有什么线索吗?

原来答案其实很简单:测试运行得如此之快,以至于在MyActorIdentify消息发送给selection之前,Actorselection后面选择已经收到它的 PoisonPill,因此被杀死。

在发送 PoisonPill 之前添加一点 Thread.sleep() 解决了这个问题。

目标参与者在发出识别请求之前被终止。这是因为 Akka only guarantees order when sending messages between a given pair of actors.

如果您在以下行上方添加 thread.sleep,识别请求应该会成功。

Thread.sleep(100)
// Act
target ! PoisonPill

请注意,可能有更好的方法来编写测试代码 - 休眠线程并不理想。

您的观看演员还应处理目标演员的 Terminated 消息,如 here 所述。