问题
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