How to restore state machine from context builded in runtime?

限于喜欢 提交于 2019-12-08 13:40:47

问题


I have a state machine

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

and I have a model, for example Order. Model persists in DB. I extract model from DB, now my model has a status Order.status == INVITATION. I want to continue processing model with statemachine, but instance of statemachine will starts processing with initial state DRAFT but I needs continue processing from status INVITATION. In other words I want to execute

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

and execute action ActionDeclined(). I don't want to persist a context of state machine in DB. I want to setting a state of stateMachine to state of my Model in runtime. How can I do that in right way? Using DefaultStateContext constructor or have an other, more beautiful way?


回答1:


One possible approach is to create the StateMachine on the fly and to rehydrate the state machine from the DB using the state of the Order. In this case you need to do the following steps:

  • Resetting the StateMachine in all regions
  • Load Order status from DB
  • Create new DefaultStateMachineContext and populate accordingly

Let's assume you have a build method, which returns new state machines for processing order events (using a StateMachineFactory), but for an existing order, it will rehydrate the state from the database.

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


来源:https://stackoverflow.com/questions/54706479/how-to-restore-state-machine-from-context-builded-in-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!