TL;DR
akkaにErlangのLinkのような機構が無いか探している。
akkaの子actorが死んだ時に親actorも巻き込まれて死ぬか確認した。
テストケース
- 子actorへのwatch無し
- poison
- stop
- exception
- 子actorへのwattch有り
- poison
- stop
- exception
code
package.scala
package net.wrap_trap.akka_samples.monitor
import akka.actor._
object Monitor {
def main(args: Array[String]): Unit = {
val superVisor = ActorSystem("test").actorOf(Props[Supervisor])
superVisor ! args
}
}
Supervisor.scala
package net.wrap_trap.akka_samples.monitor
import akka.actor.{ActorRef, Actor, Terminated, Props}
class Supervisor extends Actor {
var parent: Option[ActorRef] = None
override def preStart(): Unit = {
parent = Option(context.actorOf(Props[Parent]))
}
def receive = {
case Terminated(p) => {
println("terminated: " + p)
}
case args: Array[String] => {
val p = parent.get
context.watch(p)
p ! args
}
}
}
Parent.scala
package net.wrap_trap.akka_samples.monitor
import akka.actor.{ActorRef, Actor, Terminated, Props}
class Parent extends Actor {
var child: Option[ActorRef] = None
override def preStart(): Unit = {
child = Option(context.actorOf(Props[Child]))
}
def receive = {
case Terminated(c) => {
println("terminated: " + c)
}
case args: Array[String] => {
val c = child.get
if(args.length > 1 && args(1) == "1") {
context.watch(c)
println("start to watch: " + child)
}
c ! args(0)
}
}
}
Child.scala
package net.wrap_trap.akka_samples.monitor
import akka.actor.{ActorRef, Actor, PoisonPill}
class Child extends Actor {
def receive = {
case "poison" => {
println("message received: poison")
self ! PoisonPill
}
case "stop" => {
println("message received: stop")
context.stop(self)
}
case "exception" => throw new RuntimeException("error")
}
}
実行
子actorへのwatch無し
- poison
masayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor poison 0"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor poison 0
message received: poison
- stop
^Cmasayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor stop 0"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor stop 0
message received: stop
- exception
^Cmasayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor exception 0"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor exception 0
[ERROR] [02/06/2017 02:55:37.660] [test-akka.actor.default-dispatcher-5] [akka://test/user/$a/$a/$a] error
java.lang.RuntimeException: error
at net.wrap_trap.akka_samples.monitor.Child$$anonfun$receive$1.applyOrElse(Child.scala:15)
at akka.actor.Actor$class.aroundReceive(Actor.scala:480)
at net.wrap_trap.akka_samples.monitor.Child.aroundReceive(Child.scala:5)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
at akka.actor.ActorCell.invoke(ActorCell.scala:495)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
at akka.dispatch.Mailbox.run(Mailbox.scala:224)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
子actorへのwatch有り
- poison
^Cmasayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor poison 1"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor poison 1
start to watch: Some(Actor[akka://test/user/$a/$a/$a#1037068608])
message received: poison
terminated: Actor[akka://test/user/$a/$a/$a#1037068608]
- stop
^Cmasayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor stop 1"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor stop 1
start to watch: Some(Actor[akka://test/user/$a/$a/$a#1039911163])
message received: stop
terminated: Actor[akka://test/user/$a/$a/$a#1039911163]
- exception
^Cmasayuki@masayuki-ubuntu:~/git/akka-samples$ sbt "run-main net.wrap_trap.akka_samples.monitor.Monitor exception 1"
[info] Loading global plugins from /home/masayuki/.sbt/0.13/plugins
[info] Loading project definition from /home/masayuki/git/akka-samples/project
[info] Set current project to akka-samples (in build file:/home/masayuki/git/akka-samples/)
[info] Running net.wrap_trap.akka_samples.monitor.Monitor exception 1
start to watch: Some(Actor[akka://test/user/$a/$a/$a#-1810233518])
[ERROR] [02/06/2017 02:56:10.867] [test-akka.actor.default-dispatcher-7] [akka://test/user/$a/$a/$a] error
java.lang.RuntimeException: error
at net.wrap_trap.akka_samples.monitor.Child$$anonfun$receive$1.applyOrElse(Child.scala:15)
at akka.actor.Actor$class.aroundReceive(Actor.scala:480)
at net.wrap_trap.akka_samples.monitor.Child.aroundReceive(Child.scala:5)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)
at akka.actor.ActorCell.invoke(ActorCell.scala:495)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
at akka.dispatch.Mailbox.run(Mailbox.scala:224)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
まとめ
子actorを作っただけでは、子actorは死んでも親actorは死なない。
ErlangのLinkのように片側が死んだらLink先も死ぬ、という機構はakkaには無いのかな。