我是Akka的新手(Java lib,v2.3.9),并试图了解参与者的依赖性和后备/故障容忍度。

假设我有两个演员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消息时,他:


可能已配置为可以运行并且可以运行,在这种情况下,DarthVader将正确响应状态报告;要么
用户可能已采取措施(通过配置),使得DarthVader必须故意脱机/无响应/无操作


在后一种情况下,当假定为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 actor /线程的实例都必须处于同一状态(打开/关闭无操作模式普遍适用于所有它们),因此我不确定该解决方案是否可行与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的所有实例/角色/线程都处于无操作模式,而不仅仅是一个特定的实例。

最佳答案

几乎没有解决方案。首先,您想从config中读取DarthVader是否处于NoOp模式,然后创建actor(Typesafe Config可以正常工作)。

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);

08-26 05:16