(UML) Spring-Statemachine 在 statemachine.stop() 之后仍然是 运行

(UML) Spring-Statemachine is still running after a statemachine.stop()

我的 Spring-Statemachine 中有一个守卫。

@Bean
public Guard<String, String> myGuard() {
    return context -> {
         try {
            String x = null;
            x.length();
            return true;
         } catch (Exception e) {
             context.getStateMachine().setStateMachineError(e);
             context.getStateMachine().stop();
             throw e;
         }
     };
}

这当然是java.lang.NullPointerException
所以,在我做了一个 context.getStateMachine().stop(); 之后,我期待状态机停止。

2017-11-24 18:02:55.783  INFO 30652 --- [nio-8080-exec-1] o.s.s.support.LifecycleObjectSupport     : stopped org.springframework.statemachine.support.DefaultStateMachineExecutor@367d6b09

所以,它停止了。 但比所有其他守卫、状态和动作都在之后调用。

但是当出现错误时,我绝对不希望守卫只是切换到false,我真的很想退出机器

只有一个地区。所以,据我了解,它应该停止。

有什么办法可以解决这个问题吗?或者在发生这种情况时有什么方法可以调用 "Exit event" 之类的东西吗?

感谢您提供任何处理此问题的想法。

使用:

spring-boot: 1.5.8
spring-statemachine-uml 1.2.6

我不确定在这种情况下当有人试图阻止机器时会发生什么。老实说,我什至从未尝试过,因为您尝试做的事情毫无意义。回顾一下我最初是如何选择将上下文暴露给守卫的,可以访问机器本身,从而使停止方法可见。当机器为 运行 时,我不会尝试通过内部逻辑停止机器。我早就该考虑这个了:)

不过话虽如此,守卫实际上只有一个作用,那就是保护过渡,它应该 return 是对还是错。当调用守卫时,我们确实处理捕获异常(我们将其评估为 false,afaik),但从守卫中抛出一些东西通常是未定义的行为。

假设您执行的某些操作出现错误,那么您应该执行一些与错误相关的操作。我会即创建一个终端状态,设置转换到该终端状态,然后您可以从操作(在 catch 内)发送事件以指示机器进入该状态。通常这种错误处理不会在单根级别机器中完成,因为它通常会导致状态爆炸(您需要开始设置从所有状态到错误状态的转换)。这就是为什么通常使用子状态来处理正确的错误处理。

但是,如果您再公开一点您的用例以及您想要完成的目标,我可以尝试提供更好的示例。错误处理始终是一个特定的主题,因为它通常需要构建到您的机器设计中。从下面的状态图中可以看到我目前正在使用 spring-cloud-skipper 处理的更复杂的错误处理。这可能超出了您的问题范围,但为您接下来的评论提供了一些背景知识。

我现在正在使用这个 SpringAOP 函数捕获所有错误:

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Component;    
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Aspect
@Component
public class ErrorInterceptor {

    @Autowired
    private StateMachine<String, String> myStateMachine;

    @AfterThrowing(pointcut = "execution(* org.springframework.statemachine.guard.Guard.evaluate(*))", throwing = "ex")
    public void errorInterceptorGuard(Exception ex) {
        log.info("Error on Guard: " + myStateMachine.getState().getId() + " with Exception " + ex.toString());
        myStateMachine.setStateMachineError(ex);
    }

    @AfterThrowing(pointcut = "execution(* org.springframework.statemachine.action.Action.execute(*))", throwing = "ex")
    public void errorInterceptorAction(Exception ex) {
        log.info("Error on Action: " + myStateMachine.getState().getId() + " with Exception " + ex.toString());
        myStateMachine.setStateMachineError(ex);
    }
}

在我启动 StateMachine 的控制器中,我做了类似的事情:

if(myStateMachine.hasStateMachineError()) {
   // do something which is returning the ERROR.
}

仍然不是我想要的 100%,因为 statemachine.stop 从内部无法正常工作,但我正在处理它。