问题描述
我正在尝试创建一个状态机,该状态机将经历一系列状态,从而对某些状态加上状态转换拦截器触发进入动作。
要测试此状态机,我创建了一个Spring Boot集成测试,该测试向集成通道提供一条消息,该通道进而调用此状态机。我注意到的是,当这些动作发生时,当它开始与“ repository” bean进行交互时,它将导致状态机退出并且集成测试失败。我没有在日志中看到任何错误,但是当我引入“错误”操作时,状态机操作的行为符合预期。
我尝试将断点应用于拦截器,但是我注意到的是,由于断点而导致测试暂停时,到达repository.save(entity)行后,它将允许测试向前走,就好像我在断点处击打,但调试器本身处于动作状态。
当我引入errorAction()时,状态机的行为就会适当。我真的不知道为什么错误操作会导致机器正常完成。
配置如下
@Configuration
@EnableStateMachineFactory
public class NotificationStateMachineConfiguration
extends StateMachineConfigurerAdapter<NotificationState,NotificationEvent> {
private static final Logger LOGGER =
LoggerFactory.getLogger(NotificationStateMachineConfiguration.class);
@Autowired
private SendingAction sendingAction;
@Autowired
private TransformationAction transformationAction;
@Override
public void configure(
StateMachineConfigurationConfigurer<NotificationState,NotificationEvent> config)
throws Exception {
config.withConfiguration()
.autoStartup(false)
.taskExecutor(new SyncTaskExecutor())
.listener(new StateMachineListenerAdapter<NotificationState,NotificationEvent>() {
@Override
public void stateChanged(State<NotificationState,NotificationEvent> from,State<NotificationState,NotificationEvent> to) {
LOGGER.trace("StateChanged - From: {},To: {}",from,to);
}
});
}
@Override
public void configure(
StateMachinestateConfigurer<NotificationState,NotificationEvent> states) throws Exception {
states.withStates()
.initial(NotificationState.NEW)
.state(NotificationState.NEW)
.state(NotificationState.TRANSFORMING,transformationAction,errorAction())
.state(NotificationState.TRANSFORMATION_Failed)
.state(NotificationState.SENDING,sendingAction,errorAction())
.state(NotificationState.STAGED)
.state(NotificationState.AWAITING)
.end(NotificationState.NOT_SENT)
.end(NotificationState.RESPONSE_RECEIVED)
.end(NotificationState.ERRORS)
.end(NotificationState.NEGATIVE_RESPONCE_RECIEVED)
.end(NotificationState.SENT);
}
@Override
public void configure(
StateMachineTransitionConfigurer<NotificationState,NotificationEvent> transitions)
throws Exception {
transitions
.withExternal()
.source(NotificationState.NEW).target(NotificationState.TRANSFORMING)
.event(NotificationEvent.TRANSFORMATION_REQUESTED)
.and()
.withExternal()
.source(NotificationState.TRANSFORMING).target(NotificationState.SENDING)
.event(NotificationEvent.TRANSFORMATION_SUCCESSFULL)
.and()
.withExternal()
.source(NotificationState.TRANSFORMING).target(NotificationState.TRANSFORMATION_Failed)
.event(NotificationEvent.TRANSFORMATION_FAILURE)
.and()
.withExternal()
.source(NotificationState.SENDING).target(NotificationState.AWIATING)
.event(NotificationEvent.PROOF_OF_DELIVERY_RELEASE_REQUESTED)
.and()
.withExternal()
.source(NotificationState.SENDING).target(NotificationState.SENT)
.event(NotificationEvent.RELEASE_REQUESTED)
.and()
.withExternal()
.source(NotificationState.SENDING).target(NotificationState.STAGED)
.event(NotificationEvent.STAGE_NOTIFICATION_REQUESTED);
}
<!-- if i remove this bean the state machine dies within the interceptor when i try to utilize the repository -->
@Bean
public Action<NotificationState,NotificationEvent> errorAction() {
return context -> {
// RuntimeException("MyError") added to context
Exception exception = context.getException();
LOGGER.error(Optional.ofNullable(exception).map(Exception::getMessage)
.orElse("NO ERROR"));
};
}
}
拦截豆
@Component
public class NotificationStateInterceptor extends
StateMachineInterceptorAdapter<NotificationState,NotificationEvent> {
private static final Logger logger =
LoggerFactory.getLogger(NotificationStateInterceptor.class.getName());
private final NotificationRepository repository ;
public NotificationStateInterceptor(NotificationRepository repository) {
this.repository = eventProducrepositoryer;
}
/**
* Persist the notification that just changed state.
*
* @param state the notification has just changed to.
* @param message that triggered the state change.
* @param transition that was triggered during the stage change.
* @param stateMachine that is managing the notification's state.
*/
@Override
public void postStateChange(
State<NotificationState,NotificationEvent> state,Message<NotificationEvent> message,Transition<NotificationState,NotificationEvent> transition,StateMachine<NotificationState,NotificationEvent> stateMachine) {
/* trigger the more descriptive version */
this.postStateChange(state,message,transition,stateMachine,null);
}
/**
* Persist the notification that just changed state.
*
* @param state the notification has just changed to.
* @param message that triggered the state change.
* @param transition that was triggered during the stage change.
* @param stateMachine that is managing the notification's state.
* @param rootStateMachine in the event that this is a nested state machine.
*/
@Override
public void postStateChange(
State<NotificationState,NotificationEvent> stateMachine,NotificationEvent> rootStateMachine) {
Notification notification = getNotification(stateMachine);
if (transition.getKind() != TransitionKind.INITIAL) {
if (notification != null) {
logger.debug(
"Transitioning Notification: " + notification.getId()
+ " to State: " + state.getId());
notification.applyNewState(state.getId());
repository.save(notification);
}
}
}
}
我不确定提供errorAction()bean时是什么导致机器正确完成,而没有提供它时,应用程序也无法正确完成。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)