如何从运行时构建的上下文中恢复状态机?
How to restore state machine from context builded in runtime?
我有一个状态机
@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。
模型保留在数据库中。我从数据库中提取模型,现在我的模型状态为 Order.status == INVITATION
。我想继续使用状态机处理模型,但状态机实例将以初始状态 DRAFT 开始处理,但我需要从状态 INVITATION 继续处理。换句话说我想执行
stateMachine.sendEvent(MessageBuilder
.withPayload(Event.DECLINED)
.setHeader("orderId", order.id)
.build()
)
并执行操作 ActionDeclined()
。我不想在数据库中保留状态机的上下文。我想在运行时将 stateMachine 的状态设置为我的模型的状态。我怎样才能以正确的方式做到这一点?使用 DefaultStateContext 构造函数还是有其他更漂亮的方法?
一种可能的方法是即时创建 StateMachine
并使用 Order
的状态从数据库中重新激活状态机。
在这种情况下,您需要执行以下步骤:
- 重置所有地区的
StateMachine
- 从数据库中加载
Order
状态
- 创建新的
DefaultStateMachineContext
并相应地填充
假设您有一个构建方法,该方法 returns 用于处理订单事件的新状态机(使用 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));
});
}
我有一个状态机
@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。
模型保留在数据库中。我从数据库中提取模型,现在我的模型状态为 Order.status == INVITATION
。我想继续使用状态机处理模型,但状态机实例将以初始状态 DRAFT 开始处理,但我需要从状态 INVITATION 继续处理。换句话说我想执行
stateMachine.sendEvent(MessageBuilder
.withPayload(Event.DECLINED)
.setHeader("orderId", order.id)
.build()
)
并执行操作 ActionDeclined()
。我不想在数据库中保留状态机的上下文。我想在运行时将 stateMachine 的状态设置为我的模型的状态。我怎样才能以正确的方式做到这一点?使用 DefaultStateContext 构造函数还是有其他更漂亮的方法?
一种可能的方法是即时创建 StateMachine
并使用 Order
的状态从数据库中重新激活状态机。
在这种情况下,您需要执行以下步骤:
- 重置所有地区的
StateMachine
- 从数据库中加载
Order
状态 - 创建新的
DefaultStateMachineContext
并相应地填充
假设您有一个构建方法,该方法 returns 用于处理订单事件的新状态机(使用 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));
});
}