寻找允许类产生actor的抽象

问题描述

我有一个类向其客户提供不同类型的 Source。当 Source 运行时,应该产生一个演员,将新条目提供给相应的流。所以我的班级需要能够产生演员。我知道有两种方法可以做到这一点:使用另一个演员的 ActorContext 或使用 ActorSystem。是否有生成新actor 的通用抽象,以便我可以在我的类中注入一个帮助程序,它只允许它在需要时生成actor,而不管它是如何完成的?

我为此创建了一个 ActorSpawner 界面,目前为止效果很好:

trait ActorSpawner {

  def spawn[T](behavior: Behavior[T]): ActorRef[T]

  def spawn[T](behavior: Behavior[T],name: String): ActorRef[T]

} 

但是,自从我升级到 Akka 2.6 后,我经常收到以下错误消息:

错误 akka.actor.SupervisorStrategy - 不支持从外部访问 ActorContext 演员 [akka://...]。 Actor 当前没有处理任何消息,但是 ActorContext 是从 Thread[...]

调用

升级之前这似乎不是问题,但现在我想知道我所做的是否是可取的,或者这是否是一种反模式。

解决方法

我知道有两种方法可以做到这一点:使用另一个演员的 ActorContext 或使用 ActorSystem

我认为这适用于 Classic(即无类型)Actor API,并且通用抽象是 akka.actor.ActorRefFactoryakka.actor.ActorSystemakka.actor.ActorContext 都对其进行了扩展。这就是 def actorOf(props: Props): ActorRef 用于创建新演员的地方。

在新类型的 Actor API 中,情况不再如此。您不能从 akka.actor.typed.ActorSystem 创建演员,您只能从 akka.actor.typed.scaladsl/javadsl.ActorContext 使用 spawn* 系列方法创建它,给定演员系统的监护人/根演员除外,您可以可以由 ActorSystem(guardianBehavior: Behavior[T],name: String) 和朋友在 Scala 中创建或在 Java 中使用 ActorSystem.create(...) 等价物创建。

ActorContext 只能从拥有它的参与者的消息处理线程或从 setup 方法访问,并且生成错误日志的运行时检查自 2.6.6 .您可能从其他地方调用该对象。也许这篇文章将有助于跟踪确切位置:https://discuss.lightbend.com/t/akka-2-6-6-context-log-error-string-failed/6708/2

,

在 Typed 中,除了守护 actor(在创建 ActorSystem 时创建的那个),actor 只能由其他 actor 生成。

在很多情况下,在 actor 之外执行的代码想要生成一个 actor。为此,您可以向演员发送消息,并让该演员生成具有所需行为的演员。

如果您的 actor 的唯一目的是产生其他 actor,则 Akka 包含 SpawnProtocol,它与 ask 模式兼容:

trait ActorSpawner {
  def spawn[T](behavior: Behavior[T],name: String): Future[ActorRef[T]]

  def spawn[T](behavior: Behavior[T]): Future[ActorRef[T]] = spawn(behavior,"")
}

def spawnerFor(spawningActor: ActorRef[SpawnProtocol.Spawn])(implicit system: ActorSystem[Nothing]): ActorSpawner = {
  import system.executionContext
  import akka.actor.typed.scaladsl.AskPattern._

  implicit val timeout = Timeout(10.seconds)  // or whatever,can also make this an arg

  new ActorSpawner {
    def spawn[T](behavior: Behavior[T],name: String): Future[ActorRef[T]] =
      spawningActor.ask(SpawnProtocol.Spawn(behavior,name,Props.empty,_))
  }
}

如果您的监护人 actor 碰巧仅按需生成其他 actor,它可以实现 SpawnProtocol,在这种情况下,ActorSystem 本身就是一个 ActorRef[SpawnProtocol.Spawn],因此可以进一步简化为

def spawnerFor(system: ActorSystem[SpawnProtocol.Spawn]): ActorSpawner = {
  import system.executionContext
  import akka.actor.typed.scaladsl.AskPattern._

  implicit val timeout = Timeout(10.seconds)
  implicit val scheduler = system.scheduler

  new ActorSpawner {
    def spawn[T](behavior: Behavior[T],name: String): Future[ActorRef[T]] =
      system.ask(SpawnProtocol.Spawn(behavior,_))
  }
}
      

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...