一个演员为什么要首发两次?

Why does an actor start twice?

我只启动了一次子演员,如下所示:

object DetectorSupervisor {

  def create(): Behavior[NotUsed] =
    Behaviors.setup { context =>

      context.log.info(s"=============> Start DetectorSupervisor <=============")

      val informant = context.spawn(InformantActor.create(Vector.empty), "InformantActor")
      val stateMachine = context.spawn(DetectorStateMachine.create(informant,
        State(KafkaInactiveConfirmed, SapInactiveConfirmed)), "StateMachine")

      context.spawn(DetectorReceptionActor.create(informant), "ReceptionActor")

      context.spawn(KafkaDetectorActor.create(stateMachine, None), "KafkaActor")
      context.spawn(SapDetectorActor.create(stateMachine, None), "SapActor")

      Behavior.empty

    }

} 

并且在日志中,我可以看到,一个 actor 总是启动两次。

[INFO] [07/03/2019 22:21:35.513] [testSystem1-akka.actor.default-dispatcher-2] [akka://testSystem1/user/DetectorSupervisor] =============> Start DetectorSupervisor <=============
[INFO] [07/03/2019 22:21:37.456] [testSystem1-akka.actor.default-dispatcher-3] [akka://testSystem1/user/DetectorSupervisor/InformantActor] =============> Start InformantActor <=============
[INFO] [07/03/2019 22:21:37.460] [testSystem1-akka.actor.default-dispatcher-3] [akka://testSystem1/user/DetectorSupervisor/StateMachine] =============> Start DetectorStateMachine <=============
[INFO] [07/03/2019 22:21:37.460] [testSystem1-akka.actor.default-dispatcher-3] [akka://testSystem1/user/DetectorSupervisor/ReceptionActor] =============> Start DetectorReceptionActor <=============
[INFO] [07/03/2019 22:21:37.473] [testSystem1-akka.actor.default-dispatcher-4] [akka://testSystem1/user/DetectorSupervisor/SapActor] =============> Start SapDetectorActor <=============
[INFO] [07/03/2019 22:21:37.473] [testSystem1-akka.actor.default-dispatcher-5] [akka://testSystem1/user/DetectorSupervisor/KafkaActor] =============> Start KafkaDetectorActor <=============
[INFO] [07/03/2019 22:21:37.503] [testSystem1-akka.actor.default-dispatcher-5] [testSystem1] =============> Start KafkaDetectorStream <=============
[INFO] [07/03/2019 22:21:37.503] [testSystem1-akka.actor.default-dispatcher-4] [testSystem1] =============> Start SapDetectorStream <=============
[INFO] [07/03/2019 22:21:43.950] [testSystem1-akka.actor.default-dispatcher-3] [akka://testSystem1/user/DetectorSupervisor/InformantActor] =============> Start InformantActor <============= 

如您所见,InformantActor 启动了两次,我不明白为什么。

下面是 InformantActor 的实现:

object InformantActor {

  sealed trait InformantEvent

  case object ServerOnlineConfirmed extends InformantEvent

  case object ServerOfflineConfirmed extends InformantEvent

  case class SubscribersChanged(actor: Vector[ActorRef[ServerEvent]]) extends InformantEvent


  def create(subscribers: Vector[ActorRef[ServerEvent]]): Behavior[InformantEvent] =
    Behaviors.setup { context =>

      context.log.info(s"=============> Start InformantActor <=============")

      Behaviors.receiveMessage[InformantEvent] {
        case ServerOfflineConfirmed =>
          subscribers.foreach(a => a ! ServerOfflineApproved)
          Behavior.same
        case ServerOnlineConfirmed =>
          subscribers.foreach(a => a ! ServerOnlineApproved)
          Behavior.same
        case SubscribersChanged(actors) =>
          create(actors)
      }
    }

}

源代码托管在 https://gitlab.com/sweetsoft/plugger

我不认为,它启动了两次。

您的 create 函数是递归的,并在 case SubscribersChanged(actors) => 发生时执行。

因此,只要您的订阅者列表发生变化,您就会看到您的日志消息。

您重构 create 以将日志消息从递归中排除...像这样:

def create(initialSubscribers: Vector[ActorRef[ServerEvent]]): Behavior[InformantEvent] = {
  Behaviors.setup { context =>

    context.log.info(s"=============> Start InformantActor <=============")

    def behavior(subscribers: Vector[ActorRef[ServerEvent]]): Behavior[InformantEvent] = Behaviors.receiveMessage[InformantEvent] {
      case ServerOfflineConfirmed =>
        subscribers.foreach(a => a ! ServerOfflineApproved)
        Behavior.same
      case ServerOnlineConfirmed =>
        subscribers.foreach(a => a ! ServerOnlineApproved)
        Behavior.same
      case SubscribersChanged(actors) =>
        behavior(actors)
    }

    behavior(initialSubscribers)
  }
}