Spring State Machine触发外部事件时频繁报Retry Exhausted错误如何解决
问题根因
报错的核心原因是并发向状态机发送事件,Spring Statemachine 3.x底层基于Reactor实现,事件发送要求严格串行,你当前的两个事件发送逻辑存在并发冲突:
- 定时任务TimerAction内部调用
sendEvent发送RETRY事件,timer触发的任务运行在parallel调度器线程池 - 业务代码主动调用
sendEvent发送ERROR事件,运行在业务线程
两个线程同时发射事件触发Reactor Sink的串行校验失败,抛出Sinks$EmissionException,内部重试10次全部失败后抛出重试耗尽错误。
解决方案
1. 移除Action中主动发事件的冗余逻辑(最优先)
你当前的timer转移完全不需要自定义Action发事件,直接将timer转移的目标指向TESTING即可,从根源避免并发冲突,修改转移配置如下:
transitions // 替换原来INITIALIZING的internal timer转移 .withExternal() .source(DBStates.INITIALIZING) .target(DBStates.TESTING) .timer(100).and() .withJunction() .source(DBStates.TESTING) .first(DBStates.DOWN, isDown()) .then(DBStates.READY, isReady()) .last(DBStates.BAD_PASSWORD).and() .withExternal() .source(DBStates.BAD_PASSWORD) .target(DBStates.TESTING) .event(DBStateChanges.PASSWORD_RECEIVED).and() // 替换原来DOWN状态的internal timer转移 .withExternal() .source(DBStates.DOWN) .target(DBStates.TESTING) .timer(10000).and() .withExternal() .source(DBStates.DOWN) .target(DBStates.TESTING) .event(DBStateChanges.RETRY).and() .withExternal() .source(DBStates.INITIALIZING) .target(DBStates.TESTING) .event(DBStateChanges.RETRY).and() .withExternal() .source(DBStates.READY) .target(DBStates.TESTING) .event(DBStateChanges.ERROR);
修改完成后可直接删除冗余的TimerAction定义和对应的Bean配置。
2. 优化外部事件发送逻辑
调用Reactive API发送事件时添加错误处理,避免未处理的异常抛出:
public void triggerStateChange() { Message<DBStateChanges> m = new GenericMessage<>(DBStateChanges.ERROR); statemachine.sendEvent(Mono.just(m)) // 自定义异常处理 .doOnError(e -> log.error("状态机事件发送失败", e)) // 异常场景降级,避免错误向上传播 .onErrorResume(e -> Mono.empty()) .subscribe(); }
3. 升级依赖版本
你当前使用的Spring State Machine 3.0.1是3.x分支的早期版本,存在多个Reactor并发处理相关的已知bug,建议升级到3.0.x分支的最新维护版本,可直接修复部分底层并发问题。
4. 临时兼容方案
如果确实有场景需要在Action中发送事件,可配置状态机使用同步执行器,强制所有事件处理串行化:
@Override public void configure(StateMachineConfigurationConfigurer<DBStates, DBStateChanges> config) throws Exception { config.withConfiguration() // 同步执行器,所有事件处理都在调用线程执行,避免并发 .taskExecutor(new SyncTaskExecutor()); }
该方案会牺牲状态机的并发处理性能,仅推荐临时验证问题使用。
内容的提问来源于stack exchange,提问作者cstack
相关产品推荐
相关产品推荐

