为什么 Akka 在生成 child actor 时挂起

Why Akka hangs while spawning child actor

我正在尝试使用 Akka actors(scala 2.12.8akka-actor-typed 2.6.1

实现 A/B 测试机制

我设计为:

当 A/B 测试 actor 收到一条消息时,它将选择一个变体并将消息转发给它。

然而直到现在,我还没有设法让 root actor 产生它的 children。这是我的代码。

import akka.actor.typed.{ActorRef, ActorSystem, Behavior}
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}

import scala.util.Random

// My variants
object Ranker {
  sealed trait Command
  final case class Rank() extends Command
  def apply(rank: Int): Behavior[Command] = Behaviors.setup { context => new Ranker(context, rank) }
}

class Ranker(context: ActorContext[Ranker.Command], rank: Int) extends AbstractBehavior[Ranker.Command](context) {
  override def onMessage(msg: Ranker.Command): Behavior[Ranker.Command] = {
    println(rank)
    this
  }
}

// The root A/B Testing actor
object ABTester {
  def apply(): Behavior[Ranker.Command] = Behaviors.setup { context => new ABTester(context) }
}

class ABTester(context: ActorContext[Ranker.Command]) extends AbstractBehavior[Ranker.Command](context) {
  val rng = new Random()
  // Spawn children actors
  val rankers: Seq[ActorRef[Ranker.Command]] = Seq(Ranker(1), Ranker(2)).zipWithIndex
    .map { case (b, i) =>
      println(s"Spawning ranker $i")
      val actorRef = context.spawn(b, s"Ranker $i")
      println(s"Spawning ranker $i: Done")
      actorRef
    }

  override def onMessage(msg: Ranker.Command): Behavior[Ranker.Command] = {
    rankers(rng.nextInt(rankers.size)) ! msg
    this
  }
}

// Application entry point
object Main {
  def main(args: Array[String]): Unit = {
    val actor = ActorSystem(ABTester(), "ABTester")
    actor ! Ranker.Rank()
    Thread.sleep(5000)
  }
}

运行 此示例将打印:

Spawning ranker 0

但仅此而已,就好像第 31 行 (val actorRef = context.spawn(b, s"Ranker $i")) 从来没有 returns...

我是不是漏掉了一些关于 child 演员生成的事情?

TL;DR

Actor paths MUST:
  not start with `$`,
  include only ASCII letters
  and can only contain these special characters: -_.*$+:@&=,!~';.`

我终于发现错误了!

我没有正确设置日志记录,因此错误消息从未出现。 添加 slf4j-simple 依赖项后,会发生以下情况:

[ABTester-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
SLF4J: A number (1) of logging calls during the initialization phase have been intercepted and are
SLF4J: now being replayed. These are subject to the filtering rules of the underlying logging system.
SLF4J: See also http://www.slf4j.org/codes.html#replay
[ABTester-akka.actor.default-dispatcher-3] INFO ABTester - Spawning ranker 0
[ABTester-akka.actor.default-dispatcher-3] ERROR akka.actor.LocalActorRefProvider(akka://ABTester) - guardian failed, shutting down system
akka.actor.InvalidActorNameException: Invalid actor path element [Ranker 0], illegal character [ ] at position: 6. Actor paths MUST: not start with `$`, include only ASCII letters and can only contain these special characters: -_.*$+:@&=,!~';.
    at akka.actor.ActorPath$.validatePathElement(ActorPath.scala:98)
    at akka.actor.ActorPath$.validatePathElement(ActorPath.scala:76)
    at akka.actor.dungeon.Children.checkName(Children.scala:248)
    at akka.actor.dungeon.Children.actorOf(Children.scala:47)
    at akka.actor.dungeon.Children.actorOf$(Children.scala:46)
    at akka.actor.ActorCell.actorOf(ActorCell.scala:408)
    at akka.actor.typed.internal.adapter.ActorRefFactoryAdapter$.spawn(ActorRefFactoryAdapter.scala:41)
    at akka.actor.typed.internal.adapter.ActorContextAdapter.spawn(ActorContextAdapter.scala:66)
    at ABTester.$anonfun$rankers(ABTester.scala:31)
    [...]

演员路径(传递给 spawn 方法)不能包含任何 space.

Ranker $i 更改为 Ranker_$i 结果:

[ABTester-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
[ABTester-akka.actor.default-dispatcher-6] INFO ABTester - Spawning ranker 0
[ABTester-akka.actor.default-dispatcher-6] INFO ABTester - Spawning ranker 0: Done
[ABTester-akka.actor.default-dispatcher-6] INFO ABTester - Spawning ranker 1
[ABTester-akka.actor.default-dispatcher-6] INFO ABTester - Spawning ranker 1: Done
[ABTester-akka.actor.default-dispatcher-3] INFO Ranker - rank: 2