spring 状态机卡在加入状态

spring statemachine stuck at join state

我正在尝试制作收款机模型。

我的状态机配置如下。我省略了一些不重要的状态和事件。

@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
    states
        .withStates()
            .initial(States.INIT, initAction())
            .state(States.CONNECTED)
            .and()
            .withStates()
                .parent(States.CONNECTED)
                .initial(States.READY)
                .state(States.READY)
                .fork(States.ACCEPTING_CASH_FORK)
                .state(States.ACCEPTING_CASH)
                .join(States.ACCEPTING_CASH_JOIN)
                .choice(States.PROCESSING_CASH)
                .state(States.PRINTING_RECEIPT, printingReceiptAction(), null)
            .and()
            .withStates()
                .parent(States.ACCEPTING_CASH)
                .initial(States.BNR_CASH_IN_START)
                .state(States.BNR_CASH_IN_END)
                .end(States.BNR_CASH_IN_EXIT)
            .and()
            .withStates()
                .parent(States.ACCEPTING_CASH)
                .initial(States.CNR_CASH_IN_START)
                .state(States.CNR_CASH_IN_END)
                .end(States.CNR_CASH_IN_EXIT)
            .and();
}

@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
    transitions
        .withExternal()
            .source(States.INIT).target(States.CONNECTED)
            .and()
        .withExternal()
            .source(States.READY)
            .target(States.ACCEPTING_CASH_FORK)
            .event(Events.ACCEPT_CASH)
            .and()
        .withFork()
            .source(States.ACCEPTING_CASH_FORK)
            .target(States.BNR_CASH_IN_START).target(States.CNR_CASH_IN_START)
            .and()
        .withExternal()
            .source(States.BNR_CASH_IN_END)
            .target(States.BNR_CASH_IN_EXIT)
            .event(Events.BNR_CASH_IN_END_COMPLETED)
            .and()
        .withExternal()
            .source(States.CNR_CASH_IN_END)
            .target(States.CNR_CASH_IN_EXIT)
            .event(Events.CNR_CASH_IN_END_COMPLETED)
            .and()
        .withJoin()
            .source(States.BNR_CASH_IN_EXIT).source(States.CNR_CASH_IN_EXIT).target(States.ACCEPTING_CASH_JOIN)
            .and()
        .withExternal()
            .source(States.ACCEPTING_CASH_JOIN)
            .target(States.PROCESSING_CASH)
            .and()
        .withChoice()
            .source(States.PROCESSING_CASH)
            .first(States.DISPENSING_CASH_FORK, dispensingCashGuard(), dispensingCashAction())
            .last(States.PRINTING_RECEIPT)
            .and();
}

我还为调试目的配置了一个侦听器。

@Bean
public StateMachineListener<States, Events> listener() {
    return new StateMachineListenerAdapter<States, Events>() {
        @Override
        public void stateChanged(State<States, Events> from, State<States, Events> to) {
            log.info("State change from " + (from != null ? from.getId() : from) + " to " + to.getId());
        }

        @Override
        public void stateMachineStarted(StateMachine<States, Events> stateMachine) {
            log.info("StateMachine uuid " + stateMachine.getUuid() + " state " + stateMachine.getState().getId());
        }

        @Override
        public void transition(Transition<States, Events> transition) {
            Trigger<States, Events> trigger = transition.getTrigger();
            State<States, Events> source = transition.getSource();
            State<States, Events> target = transition.getTarget();
            log.info("Transition trigger " + (trigger != null ? trigger.getEvent() : trigger) + 
                " source " + (source != null ? source.getId() : source) + 
                " target " + (target != null ? target.getId() : target) + " kind " + transition.getKind());
        }

    };
}

问题出在ACCEPTING_CASH_JOIN join 当达到2个状态时状态机应该处于哪个BNR_CASH_IN_EXITCNR_CASH_IN_EXIT。但是在日志中状态机没有达到它。

2017-06-30 19:59:06.891  INFO 3776 --- [       Thread-9] k.d.c.config.StateMachineConfiguration   : StateMachine uuid 52e51cf0-06f0-4efa-8d05-1717bf869239 state CONNECTED
2017-06-30 19:59:06.891  INFO 3776 --- [       Thread-9] k.d.c.config.StateMachineConfiguration   : State change from null to CNR_CASH_IN_END
2017-06-30 19:59:06.892  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : Transition trigger CNR_CASH_IN_END_COMPLETED source CNR_CASH_IN_END target CNR_CASH_IN_EXIT kind EXTERNAL
2017-06-30 19:59:06.892  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : State change from CNR_CASH_IN_END to CNR_CASH_IN_EXIT

2017-06-30 19:59:06.924  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : StateMachine uuid 52e51cf0-06f0-4efa-8d05-1717bf869239 state CONNECTED
2017-06-30 19:59:06.924  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : State change from null to BNR_CASH_IN_END
2017-06-30 19:59:07.146  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : Transition trigger BNR_CASH_IN_END_COMPLETED source BNR_CASH_IN_END target BNR_CASH_IN_EXIT kind EXTERNAL
2017-06-30 19:59:07.146  INFO 3776 --- [       Thread-8] k.d.c.config.StateMachineConfiguration   : State change from BNR_CASH_IN_END to BNR_CASH_IN_EXIT

2017-06-30 19:59:27.239 DEBUG 3776 --- [  XNIO-2 task-4] k.d.c.w.rest.StateMachineQueryResource   : [CONNECTED, ACCEPTING_CASH, BNR_CASH_IN_EXIT, CNR_CASH_IN_EXIT]

最后一行是我通过在状态机上调用方法来检查当前状态的方法 stateMachine.getState().getIds()

你介意分别尝试两件事吗

  1. 将这些结束状态更改为正常状态。
  2. 不是按结束状态加入,而是按其父状态加入 (ACCEPTING_CASH)。

我还没有检查是否有针对这个特定用例的测试来验证它是否应该工作。理论是终端状态不能有传出转换,因此 join 可能不起作用。