发布 - 订阅Akka Actor FSM无效

时间:2015-07-31 15:39:39

标签: scala akka actor publish-subscribe fsm

我有这个特性的基本特征和子类。每个子类使用自己的事件类订阅事件流。例如 ActorFSM1 关心 InitEventImpl1 ,因此它将订阅此事件。 但是,当我发布这些特定事件时,没有演员接收它们。

trait InitEvent
case class InitEventImpl1 extends InitEvent
case class InitEventImpl2 extends InitEvent

class ActorFSM[T <: InitEvent] extends FSM[s, Data] {}
class ActorFSM1 extends ActorFSM[InitEventImpl1] {
  context.system.eventStream.subscribe(self, classOf[InitEventImpl1] )
}
class ActorFSM2 extends ActorFSM[InitEventImpl2] {
  context.system.eventStream.subscribe(self, classOf[InitEventImpl2] )
}

当我尝试按如下方式发布它们时,没有人收到消息。我究竟做错了什么?

 val system = ActorSystem("system")
 val actor = system.actorOf(Props(new ActorFSM1()) )
 system.eventStream.publish(InitEventImpl1())

1 个答案:

答案 0 :(得分:3)

无法保证在发布消息时已初始化actor,也无法保证在subscribe之前调用publish。这是一个经典的演员 - 建筑竞赛条件。 ActorRef的创建是同步的,但实际Actor的创建 - 在订阅发生时 - 是异步的,并且可能在创建ActorRef之后很好地发生。您可以通过向流发送一堆消息来测试这一点,以查看Actor最终是否会看到其中一些消息。

trait InitEvent
case class InitEventImpl1(id: Int) extends InitEvent

class ActorFSM[T <: InitEvent] extends FSM[s, Data] {}
class ActorFSM1 extends ActorFSM[InitEventImpl1] {
  context.system.eventStream.subscribe(self, classOf[InitEventImpl1] )
  def receive: Receive = {
    case InitEventImpl1(id) => println(id)
  }
}

然后发布一堆消息,看看它是否最终得到了一些消息:

val system = ActorSystem("system")
val actor = system.actorOf(Props(new ActorFSM1()) )
Seq.tabulate(100)(InitEventImpl1(_)).foreach(system.eventStream.publish)

如果Actor绝对必须收到该消息,我建议您直接将消息发送到ActorRef或等待来自Actor的消息,以表明它已准备好接收消息。

另一方面,你在这里使用泛型并不能帮助你。您想要做的似乎是使用subscribe调用中的泛型参数和receive。这可以通过一些反思魔法来完成:

import akka.actor.Actor
import scala.reflect._

class Test[E <: InitEvent : ClassTag] extends Actor {
   context.system.eventStream.subscribe(self, classTag[E].runtimeClass)
   def receive: Receive = {
     case message: E => println(message)
   }
}

然后在创建ActorRef

时指定消息类型
val myTypeActor = system.actorOf(Props(new Test[InitEventImpl1]))
myTypeActor ! InitEventImpl1 // Will be processed
myTypeActor ! InitEventImpl2 // Will not be processed