为什么 Akka 在生成 child actor 时挂起
Why Akka hangs while spawning child actor
我正在尝试使用 Akka actors(scala 2.12.8
、akka-actor-typed 2.6.1
)
实现 A/B 测试机制
我设计为:
- 1 A/B 测试根演员
- 2 变体演员,child任 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
我正在尝试使用 Akka actors(scala 2.12.8
、akka-actor-typed 2.6.1
)
我设计为:
- 1 A/B 测试根演员
- 2 变体演员,child任 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