Akka:沟通和处理演员之间的特殊状态(非错误)

时间:2015-04-23 14:57:29

标签: java akka actor

我是Akka(Java lib,v2.3.9)的新手,我正在尝试理解actor依赖性和后备/容错。

假设我有两个演员,StormTrooperDarthVader

// Groovy pseudo-code
class StatusReport {
    private final Report report

    StatusReport(Input report) {
        super()
        this.report = deepClone(report)
    }

    Input getReport() {
        deepClone(this.report)
    }
}

class StormTrooper extends UntypedActor {
    ActorRef lordVader  // Injected with reference to DarthVader

    @Override
    void onReceive(Object message) {
        if(message instanceof PerformReport) {
            PerformReport pr = message as PerformReport
            Report report = ReportUtils.generateReport(pr.config)
            StatusReport statusReportMsg = new StatusReport(report)
            lordVader.tell(statusReportMessage, ...)
        }
    }
}

class DarthVader extends UntypedActor {
    @Override
    void onReceive(Object message) {
        if(message instanceof StatusReport) {
            // Do something meaningful with the status report.
        }
    }
}

在某些情况下,DarthVader基本上是NULL,应该是无操作。也就是说:当StormTrooper决定向StatusReport发送DarthVader消息时,他:

  1. 可能已配置为活动且功能正常,在这种情况下DarthVader将正确响应状态报告;或
  2. 用户可能已采取行动(通过配置),DarthVader必须故意离线/无响应/无操作
  3. 在后一种情况下,当DarthVader 假设时(我强调这是为了区分这个用例DarthVader应该是活着/运行但是在故障/错误状态)为无操作,我不知道如何将其传达回StormTrooper,如果fizzBuzz#derp()为无操作,则必须致电DarthVader

    解决方案#1:基于状态的无操作检测

    class StormTrooper extends UntypedActor {
        ActorRef lordVader  // Injected with reference to DarthVader
    
        @Override
        void onReceive(Object message) {
            if(message instanceof PerformReport) {
                if(lordVader.isNoOp) {
                    fizzBuzz.derp()
                } else {
                    PerformReport pr = message as PerformReport
                    Report report = ReportUtils.generateReport(pr.config)
                    StatusReport statusReportMsg = new StatusReport(report)
                    lordVader.tell(statusReportMessage, ...)
                }
            }
        }
    }
    
    class DarthVader extends UntypedActor {
        boolean isNoOpMode = false
    
        @Override
        void onReceive(Object message) {
            if(message instanceof StatusReport) {
                if(!isNoOpMode) {
                    // Do something meaningful with the status report.
                }
    
                // Obviosuly, if we are in no-op mode, do nothing.
            }
        }
    }
    

    我的不确定性是DarthVader个参与者/线程的所有实例必须处于相同状态(无操作模式开启/关闭适用于所有人),所以我不确定这种解决方案甚至可以与Akka最佳实践保持一致。

    解决方案#2:抛出专门的异常

    class StormTrooper extends UntypedActor {
        ActorRef lordVader  // Injected with reference to DarthVader
    
        @Override
        void onReceive(Object message) {
            if(message instanceof PerformReport) {
                try {
                    PerformReport pr = message as PerformReport
                    Report report = ReportUtils.generateReport(pr.config)
                    StatusReport statusReportMsg = new StatusReport(report)
                    lordVader.tell(statusReportMessage, ...)
                } catch(DarthVaderNoOpException dvnoExc) {
                    fizzBuzz.derp()
                }
            }
        }
    }
    
    class DarthVader extends UntypedActor {
        boolean isNoOpMode = false
    
        @Override
        void onReceive(Object message) {
            if(message instanceof StatusReport) {
                if(!isNoOpMode) {
                    // Do something meaningful with the status report.
                } else {
                    throw new DarthVaderNoOpException()
                }
            }
        }
    }
    

    但是使用异常来控制流是一般的禁忌,甚至可能触发内置的Akka主管行为(对异常做出反应可能导致Akka重启StormTrooper等。)

    解决方案#3:发回响应消息

    class StormTrooper extends UntypedActor {
        ActorRef lordVader  // Injected with reference to DarthVader
    
        @Override
        void onReceive(Object message) {
            if(message instanceof PerformReport) {
                PerformReport pr = message as PerformReport
                Report report = ReportUtils.generateReport(pr.config)
                StatusReport statusReportMsg = new StatusReport(report)
                lordVader.tell(statusReportMessage, ...)
            } else if(message instanceof DarthVaderNoOp) {
                fizzbuzz.derp()
            }
        }
    }
    
    class DarthVader extends UntypedActor {
        ActorRef stormTrooper
        boolean isNoOpMode = false
    
        @Override
        void onReceive(Object message) {
            if(message instanceof StatusReport) {
                if(!isNoOpMode) {
                    // Do something meaningful with the status report.
                } else {
                    DarthVaderNoOp noOpMsg = new DarthVaderNoOp()
                    stormTrooper.tell(noOpMsg, ...)
                }
            }
        }
    }
    

    但这似乎是一个麻烦,讨厌的解决方案。

    所以我问:DarthVaderStormTrooper表明它处于无操作模式的最佳方式是什么,以便StormTrooper知道呼叫fizzBuzz.derp()?请记住,如果DarthVader处于无操作模式,DarthVader的所有实例/参与者/线程都处于无操作模式,而不仅仅是一个特定实例。

1 个答案:

答案 0 :(得分:1)

几乎没有可能的解决方案。首先,您希望从配置中读取DarthVader处于NoOp模式,然后创建actor(Typesafe配置将正常工作)。

Config vader = conf.getConfig("vader");
bool isNoOpMode = vader.getBoolean("state");

因此,您可以为应用程序设置它。

对于DarthVader他自己,正如你所说,你可以做一个讨厌的解决方案(回复StormTrooper),或者利用你的第一种方法与Ask模式相结合。您将向DarthVader发送报告并返回Future,等待DarthVader响应。

Timeout timeout = new Timeout(Duration.create(5, "seconds"));
Future<Object> future = Patterns.ask(lordVader, statusReportMsg, timeout);

请注意,您不想调用Await方法,而是处理onComplete内的响应,例如:

final ExecutionContext ec = system.dispatcher();

future.onComplete(new OnComplete<VaderResponse>() {
  public void onComplete(Throwable failure, VaderResponse result) {
    if (failure != null) {
      // Derp
    } else {
      // Report acknowledged
    }
  }
}, ec);