我有这个特性的基本特征和子类。每个子类使用自己的事件类订阅事件流。例如 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())
答案 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