【问题标题】:Spring State Machine - How to navigate to an error final state if any action has an errorSpring State Machine - 如果任何操作有错误,如何导航到错误最终状态
【发布时间】:2019-02-17 08:15:04
【问题描述】:

假设我们有 3 个状态 S1、S3、S3 和一个错误状态 E1。 S* 状态具有分别执行 A1、A2、A3 的动作。如果 A1、A2、A3 中的任何一个导致抛出异常,则状态机应该转到 E1。有没有一种方法可以定义一个通用转换,如果任何操作引发异常,则转到 E1?还是我必须明确说明每个状态的转换

states.withStates()
                .initial(START)
                .end(END)
                .end(ERROR)
                .state(S1, A1())
                .state(S2, A2())
                .state(S3, A3())



//Is this the only way of defining error transition? Can I dry it up?
    transitions
       .withExternal()
       .source(S1)
       .event(ErrorEvent)
       .target(E1)

     .and()

        .withExternal()
           .source(S2)
           .event(ErrorEvent)
           .target(E1)

    .and()

        .withExternal()
          .source(S3)
          .event(ErrorEvent)
          .target(E1)

我希望有一种方法可以以某种方式将其干燥。如果我有 10 个州,那么这样做就太重复了。

【问题讨论】:

  • 我也一直在寻找解决这个问题的方法,但我找不到任何有用的东西。我认为使用 SM 配置适配器是不可能的。

标签: spring-statemachine


【解决方案1】:

目前没有使用状态机生成器的通用方法来执行此操作。 根据定义,每个状态转换都应该在配置中明确定义。

这是另一个问题来讨论这是否是 SM 世界中的正确方法:

如果 A1、A2、A3 中的任何一个导致抛出异常,则状态 机器应该去E1。

SM 应该进入错误状态还是应该保持相同状态或恢复到先前的状态等等,这是值得商榷的。 我的理解是,当错误发生在任何其他状态时,转换到一个常见的错误状态不是一个好方法。

这实际上取决于您需要如何处理错误。 例如,如果您想在调用代码上发出信号或在 stateMachine 之外传播错误,您可以为此使用 StateContext 或 SM ExtendedContext。 您可以插入自定义标志(例如“hasError”)和异常本身,并将其公开给调用者代码,但这不是很优雅。有人应该在每次调用时检查该标志的存在并通知调用者代码(或者调用者代码本身应该检查它,这很丑陋)。

另一种方法是清除 stateContext 并保持相同的状态,等待一些重试逻辑启动。 或者在您的 errorAction 中,您可以将 ErrorEvent 发送到您的 SM 并传递 SM 上下文中所需的任何信息,我相信这是您选择的方法。

无论哪种方式 - 所有转换都应存在于 StateMachineModel 中。 此模型可以使用构建器方法创建,也可以通过编程方式创建(例如,迭代所有现有状态并只定义 1 个额外转换到错误状态会更容易)。

@Override
public StateMachineModel<String, String> build() {
    ConfigurationData<String, String> configurationData = new ConfigurationData<>();
    Collection<StateData<String, String>> stateData = new ArrayList<>();
    stateData.add(new StateData<String, String>("S1", true));
    stateData.add(new StateData<String, String>("S2"));
    stateData.add(new StateData<String, String>("S3"));
    stateData.add(new StateData<String, String>("ERROR_STATE"));
    StatesData<String, String> statesData = new StatesData<>(stateData);
    Collection<TransitionData<String, String>> transitionData = new ArrayList<>();
    transitionData.add(new TransitionData<String, String>("S1", "S2", "E1"));
    stateData.forEach(state -> {
        if (state.getState() != ERROR_STATE) {
            transitionData.add(new TransitionData<String, String>(state.getState(), "ERROR_STATE", "ERROR_EVENT"));
        }
    });
    TransitionsData<String, String> transitionsData = new TransitionsData<>(transitionData);
    StateMachineModel<String, String> stateMachineModel = new DefaultStateMachineModel<String, String>(configurationData,
            statesData, transitionsData);
    return stateMachineModel;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    • 1970-01-01
    • 2016-03-28
    相关资源
    最近更新 更多