不同的Akka Actor实例接收消息

时间:2016-11-24 09:17:53

标签: scala akka guice spray

我在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)

       }

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

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的同一个实例将收到这两个消息。

我做错了什么?

2 个答案:

答案 0 :(得分:2)

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

您必须注入actor系统,并在每次需要时查找actor ref。稍微改进可能是添加一项服务,这将包括演员系统和与演员的沟通。然后注入这个新服务而不是演员等。

这就是framework的作者描述的方式:

答案 1 :(得分:0)

我通过添加@Singleton注释来解决问题,以提供GeneActorRef方法

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