如何从运行时构建的上下文还原状态机



我有状态机

@EnableStateMachine
@Configuration
public class StateMachineConfiguration extends EnumStateMachineConfigurerAdapter<Status, Event> {
    @Override
    public void configure(StateMachineStateConfigurer<Status, Event> states) throws Exception {
        states.withStates()
                .initial(Status.DRAFT)
                .states(EnumSet.allOf(Status.class));
    }
    @Override
    public void configure(StateMachineTransitionConfigurer<Status, Event> transitions) throws Exception {
        transitions
                .withExternal()
                .target(Status.INVITATION).source(Status.DRAFT)
                .event(Event.INVITED)
                .guard(new Guard())
                .action(new ActionInvited())
                .and()
                .withExternal()
                .target(Status.DECLINED).source(Status.INVITATION)
                .event(Event.DECLINED)
                .action(new ActionDeclined());
    }
    @Override
    public void configure(StateMachineConfigurationConfigurer<Status, Event> config) throws Exception {
        config.withConfiguration().autoStartup(true);
    }
}

我有一个模型,例如 order 。模型在DB中持续存在。我从DB中提取模型,现在我的模型具有状态Order.status == INVITATION。我想继续使用statemachine处理模型,但是Statemachine的实例将开始使用初始状态草稿进行处理,但是我需要继续从状态邀请继续处理。换句话说,我想执行

stateMachine.sendEvent(MessageBuilder
  .withPayload(Event.DECLINED)
  .setHeader("orderId", order.id)
  .build()
)

并执行操作ActionDeclined()。我不想在数据库中坚持状态机的上下文。我想在运行时设置statemachine状态。我该怎么以正确的方式做到这一点?使用DefaultStateContext构造函数或具有其他更漂亮的方式?

一种可能的方法是使用Order的状态从DB中飞出StateMachine并从DB中补充状态机。在这种情况下,您需要执行以下步骤:

  • 在所有区域重置StateMachine
  • 加载Order状态来自DB
  • 创建新的DefaultStateMachineContext并相应填充

让我们假设您有一个构建方法,该方法返回新的状态计算机处理订单事件(使用statemachineFactory),但是对于现有订单,它将从数据库中补充状态。

StateMachine<Status, Event> build(long orderId) {
  orderService.getOrder(orderId) //returns Optional
  .map(order -> {
     StateMachine<Status, Event> sm = stateMachineFactory.getStateMachine(Long.toString(orderId));
     sm.stop();
     rehydrateState(sm, sm.getExtendedState(), order.getStatus());
     sm.start();
     return sm;
   })
  .orElseGet(() -> createNewStateMachine(orderId);
}

void rehydrateState(StateMachine<Status, Event> newStateMachine, ExtendedState extendedState, Status orderStatus) {
  newStateMachine.getStateMachineAccessor().doWithAllRegions(sma ->
   sma.resetStateMachine(new DefaultStateMachineContext<>(orderStatus, null, null, extendedState));
  });
}

最新更新