【问题标题】:Different Akka Actor instances receive messages不同的 Akka Actor 实例接收消息
【发布时间】:2016-11-24 09:17:52
【问题描述】:

我在 Spray 项目中使用 Guice 创建了依赖注入,如 this 教程中所述。

我的 Guice 模块:

class ActorsModule extends AbstractModule with ScalaModule  with GuiceAkkaActorRefProvider {
override def configure() {
  bind[Actor].annotatedWith(Names.named(GenesActor.name)).to[GenesActor]
  bind[Actor].annotatedWith(Names.named(SearchSegmentsActor.name)).to[SearchSegmentsActor]
  bind[Actor].annotatedWith(Names.named(CollectionsFinderActor.name)).to[CollectionsFinderActor]
  bind[Actor].annotatedWith(Names.named(HttpServiceActor.name)).to[HttpServiceActor]
}

@Provides
@Named(GenesActor.name)
def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef =   provideActorRef(system, GenesActor.name)

@Provides
@Named(SearchSegmentsActor.name)
def provideSearchSegmentsActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, SearchSegmentsActor.name)

@Provides
@Named(CollectionsFinderActor.name)
def provideCollectionsFinderActorRef(@Inject() system: ActorSystem):   ActorRef = provideActorRef(system, CollectionsFinderActor.name)

}

我有 http 服务参与者,它通过注入其他参与者并将消息转发给这些参与者:

object HttpServiceActor extends NamedActor {
  override final val name: String = "HttpServiceActor"
}

class HttpServiceActor @Inject()(@Named(SearchSegmentsActor.name) searchSegmentsActor: ActorRef,
                             @Named(CollectionsFinderActor.name) collectionsFinderActor: ActorRef,
                             @Named(GenesActor.name) genesActor: ActorRef)
                                extends Actor with SearchHttpService with ActorLogging {

                 def actorRefFactory = context

                 def receive = runRoute(
                      sprayRoute(searchSegmentsActor, collectionsFinderActor, genesActor) ~
                         staticRoute)

       }

我需要定期向其中一个注入的参与者发送消息,所以我的主要方法如下所示:

val injector = Guice.createInjector(
  new ConfigModule(),
  new AkkaModule(),
  new DaoModule(),
  new ActorsModule()
)

implicit val system = injector.getInstance(classOf[ActorSystem])

val service = system.actorOf(GuiceAkkaExtension(system).props(HttpServiceActor.name))
val collectionsActor = system.actorOf(GuiceAkkaExtension(system).props(CollectionsFinderActor.name))
system.scheduler.schedule(0 seconds, 1 minutes, collectionsActor, new RefreshCollections())

IO(Http) ! Http.Bind(service, system.settings.config.getString("app.interface"), system.settings.config.getInt("app.port"))

实际上我看到我有 2 个 CollectionsFinderActor 实例 - 一个每 1 分钟接收预定消息,第二个接收由 HttpServiceActor 转发的消息

当然,这不是我所期望的——我希望 CollectionsFinderActor 的同一个实例同时接收这两条消息。

我做错了什么?

【问题讨论】:

    标签: scala akka guice spray


    【解决方案1】:

    快速猜测。如果我记得的话,guice 默认情况下会在您每次请求时创建一个新的服务实例。至少,它不承诺重复使用它们。

    您将不得不注入actor系统,并在每次需要时查找actor ref。轻微的改进可能是添加一个服务,该服务将包装参与者系统和与参与者的通信。然后注入这个新服务而不是演员等。

    framework的作者是这样描述的:

    【讨论】:

    • 他们写道,你不应该让演员单例允许 Akka 重新创建他们
    • 您可以查看 Play 文档。他们描述了如何集成 akka guice 和 play,也许你会发现一些想法可以在你的项目中重用 playframework.com/documentation/2.5.x/ScalaAkka
    • 不幸的是,这一切都无济于事——我得到了不同的演员实例
    • 当你需要从不同的点向某个actor发送消息时,你不必注入它们。如果那是参与者之外的应用程序部分,则将参与者系统本身注入其中,并按名称/路径查找目标参与者。 @PavelBernshtam
    • 我从另一个actor发送来自actor的消息。我尝试了两种方法 - 将 actor ref 注入第一个 actor 或注入 ActorSystem 并每次都获取对 actor ref 的引用。在这两种情况下,我不同的 Actor 实例都会收到每条消息
    【解决方案2】:

    我通过在provideGenesActorRef 方法中添加@Singleton 注释解决了这个问题

    @Provides
    @Named(GenesActor.name)
    def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef =   provideActorRef(system, GenesActor.name)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      • 1970-01-01
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 2011-09-06
      相关资源
      最近更新 更多