

親-子のアクターで、withRouter()を使いルーターを設定すると子がcontext.parentを参照できなくなります。解決方法と理由が知りたくて質問しました。

まずcontext.parentが参照できる例

[code]

    case object Ping
    case object Pong
    
    object Sample1 {
    
      def run() = {
        val system = ActorSystem()
        val parent = system.actorOf(Props(classOf[Parent]), "parent")
        parent ! Ping
      }
    
      class Parent extends Actor {
    
        val worker = context.actorOf(Props(classOf[Child]), "child")
    
        def receive = {
          case Ping =>
            worker ! Ping
          case Pong =>
            println("PONG!")
        }
      }
    
      class Child extends Actor {
    
        def receive = {
          case Ping =>
            println(context.parent)
            context.parent ! Pong
        }
      }
    
    }
    
[/code]

printで

> Actor[akka://default/user/parent#-1479915643]  
>  PONG!

このように出力がされ、期待通りに動いてます。

workerを作るところで、withRouterを設定すると

[code]

    val worker = context.actorOf(Props(classOf[Child]).withRouter(RoundRobinPool(3)), "child")
    
[/code]

結果が

> Actor[akka://default/user/parent/child#-761629135]

このようにPONG!が出なくなり、context.parentが自身のchildになってます。

もちろんsenderでやれば送り元の親に返せるんですが、postRestart等でフックしたときにsenderだと親に返せなくて、context.parentにしたらこの現象に遭遇したという感じです。

詳しい方ご教授ください。

よろしくおねがいします m(_ _ )m


CC BY-SA 3.0
2015-04-23T08:54:52.800
9508
2015-08-21T19:18:21.163
2015-04-23T16:14:17.640
56
9460
question
scala akka
akkaでwithRouterするとcontext.parentがとれなくなる


自分もあまり詳しくないですが、公式ドキュメントに以下のような例や記述があるので

[code]

    val escalator = OneForOneStrategy() {
      case e ⇒ testActor ! e; SupervisorStrategy.Escalate
    }
    val router = system.actorOf(RoundRobinPool(1, supervisorStrategy = escalator).props(
      routeeProps = Props[TestActor]))
    
[/code]

  * <http://doc.akka.io/docs/akka/2.3.10/scala/routing.html#supervision>
  * <https://github.com/akka/akka/blob/v2.3.10/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala#L143-L149>

router作成時の`RoundRobinPool`のコンストラクタなどを経由して、自分で設定するとかでしょうか？


CC BY-SA 3.0
2015-04-23T15:24:44.380
9514
2015-04-23T15:24:44.380
56
9508
answer


  * 親 / 子

という階層が、routerを生成した場合には

  * 親 / router / 子

となるので、この場合には子からparentを見たらrouterになります。context.parentの動作としては、おかしくなってはいません。(子という名前のまま統一しましたが、routerを使った方では階層上は、親から見たら孫になりました)  
公式の説明で該当するのは、
<http://doc.akka.io/docs/akka/2.3.10/scala/routing.html#supervision> の以下の部分です。

> Routees that are created by a pool router will be created as the router's
> children.

質問主さんのコードでは、routerにchildと名前を付けているので、context.parentとして表示されているのはChildクラスのActorではなくて、childという名前のrouterです。

[code]

    val worker = context.actorOf(Props(classOf[Child]).withRouter(RoundRobinPool(3)), "router")
    
[/code]

これで生成したとして、parentとselfをprintlnするようにしてPingを3連射してみると、router/$aとかrouter/$bとかに配置されているのがわかります。

[code]

    self: Actor[akka://default/user/parent/router/$a#-1029801143]
    parent: Actor[akka://default/user/parent/router#-1266735066]
    self: Actor[akka://default/user/parent/router/$b#1593806271]
    parent: Actor[akka://default/user/parent/router#-1266735066]
    self: Actor[akka://default/user/parent/router/$c#1456555264]
    parent: Actor[akka://default/user/parent/router#-1266735066]
    
[/code]

senderでダメなケースの詳細がわかりませんが、そちらを突き詰めた方がよいのかもしれません。


CC BY-SA 3.0
2015-04-23T16:45:33.083
9516
2015-04-23T16:45:33.083
799
9508
answer