akka 切换到不同的行为未按预期工作

rhfm7lfc  于 2022-11-05  发布在  其他
关注(0)|答案(1)|浏览(174)

所以我在Akka中使用了不同的行为。当我执行这段代码时:

@Override
public Receive<CommonCommand> createReceive() {
    return notYetStarted();
}

public Receive<CommonCommand> notYetStarted() {
    return newReceiveBuilder()

            .onMessage(RaceLengthCommand.class, message -> {

                // business logic

                return running();
            })

            .build();
}

public Receive<CommonCommand> running() {
    return newReceiveBuilder()

            .onMessage(AskPosition.class, message -> {

                if ("some_condition") {

                    // business logic

                    return this;

                } else {

                    // business logic

                    return completed(completedTime);
                }

            })

            .build();

}

public Receive<CommonCommand> completed(long completedTime) {
    return newReceiveBuilder()

            .onMessage(AskPosition.class, message -> {

                // business logic

                return this;
            })

            .build();

}

我得到了以下日志:

21:46:41.038 [monitor-akka.actor.default-dispatcher-6] INFO akka.actor.LocalActorRef - Message [learn.tutorial._5_racing_game_akka.RacerBehavior$AskPosition] to Actor[akka://monitor/user/racer_1#-1301834398] was unhandled. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

最初,RaceLengthCommand消息被发送到notYetStarted()行为。这工作正常。然后,这个行为应该转换到running()行为,第二个行为应该接收消息AskPosition
但是根据我的测试,AskPosition消息被传递给notYetStarted()行为,这与我对这个概念的整体理解相矛盾。
我通过从running()行为中复制onMessage()部分并粘贴到notYetStarted()行为中来确认这一点。
很显然,即使在我切换了行为之后,notYetStarted()行为也确实在接收消息?为什么会发生这种情况??

rekjcdws

rekjcdws1#

看起来您的actor定义混合了OO和函数样式,并且在同一actor中使用这些样式之间的相互作用中遇到了一些问题。这种混淆的一些原因是Java API中的ReceiveBehavior而不是AbstractBehavior。这可能是API早期发展的痕迹(我已经建议Akka的维护者在2.7中删除这个遗迹(由于二进制兼容性,这是最早的删除时间);与其中一些应用程序的通信还没有得出这种区别的原因,类似的Scala API中也没有这种区别)。
免责声明:我倾向于只使用Scala函数API来定义actor。
在参与者模型中,参与者的状态(即它的字段)和行为(它如何响应它接收到的下一条消息)之间存在二元性:对于参与者之外的世界来说,它们是同一个,因为观察参与者状态的唯一方法(忽略像堆转储这样的东西)是观察它对消息的响应。当然,实际上,当前行为是参与者运行时表示中的一个字段,而在函数定义中,行为通常有状态字段。
行为定义的OO风格倾向于:

  • 执行元中的可变字段
  • 当前行为是不可变的(行为可以基于字段做出决定)

行为定义的功能风格倾向于:

  • 执行元中没有可变字段
  • 更新行为(这是一个隐式可变字段)

(the这一区别类似于命令式编程(具有一个while/for循环,其中一个变量被更新)与函数式编程(偏好于定义一个递归函数,编译器在后台将其转换为一个循环)。
AbstractBehavior API似乎假定消息处理程序是createReceive():在AbstractBehavior中返回this意味着返回到createReceive()。相反,在函数样式中的Behaviors.same()意味着“无论当前行为是什么,都不要改变它”。在一个AbstractBehavior中存在多个sub-Behavior/Receive的情况下,这个差异很重要(当AbstractBehavior中有一个Receive时,这个差异就不重要了)。

  • TL;DR:如果在AbstractBehavior中定义多个消息处理程序,则在消息处理程序中首选return Behaviors.same而不是return this。或者:每个AbstractBehavior仅定义一个消息处理程序。*

相关问题