SpringBoot中Chaos Monkey测试数据库重试失效问题及替代方案咨询
问题描述
我在微服务中实现了数据库记录保存时的重试机制(通过@Retryable注解配置,针对SQLException,最大重试3次,间隔1秒),该机制已正常工作。但我希望在不关闭数据库的测试环境中验证它,因此引入了Chaos Monkey。
相关代码与配置
DemoService类代码
public class DemoService { @Autowired private DemoRepo demoRepo; static private int i=0; @Retryable(value={SQLException.class},maxAttempts = 3, backoff = @Backoff(delay = 1000)) public Demo save(Demo demo){ log.info("Retry is working"+(i+1)); return demoRepo.save(demo); } }
application.yml配置文件
spring: jpa: hibernate: ddl-auto: update datasource: url: jdbc:mysql://localhost:3306/chaostest username: root password: 1234 driver-class-name: com.mysql.cj.jdbc.Driver profiles: active: chaos-monkey chaos: monkey: enabled: true assaults: exceptionsActive: true exception: type: java.sql.SQLException level: 5 watcher: demoRepo: true logging: level: de: codecentric: spring: boot: chaos: monkey: DEBUG
当前问题:Chaos Monkey并未触发数据库异常,事务首次执行就直接成功,无法验证重试机制是否正常工作。咨询以下两点:
- 需要修改哪些配置或代码才能让Chaos Monkey正常生效?
- 有无无需关闭数据库的其他测试方法?
解决方案
1. 调整Chaos Monkey配置与代码使其生效
- 修正Watcher配置:Chaos Monkey针对Spring Data Repository的监听,建议显式开启
repositories类型的Watcher,确保能识别到Repo Bean。修改配置:chaos: monkey: watcher: repositories: true demoRepo: true - 调高异常触发概率:当前
level:5仅5%的触发概率,测试阶段建议改为level:100(100%触发),确保每次调用都能抛出异常,验证完成后再调回:chaos: monkey: assaults: level: 100 - 匹配实际抛出的异常类型:Hibernate会将
SQLException包装为PersistenceException,导致@Retryable无法捕获。可以同步调整两处:- 修改
@Retryable的异常范围:@Retryable(value={SQLException.class, PersistenceException.class}) - 让Chaos Monkey抛出
PersistenceException:chaos: monkey: assaults: exception: type: javax.persistence.PersistenceException
- 修改
- 确认代理与依赖兼容性:检查Spring Boot与Chaos Monkey版本是否匹配(比如Spring Boot 3.x对应Chaos Monkey 2.x),同时确保
DemoRepo是被Spring正确代理的Bean,通过DEBUG日志查看Chaos Monkey是否成功注册了对该Bean的监听。
2. 无需关闭数据库的其他测试方法
- Mock数据层抛出异常:在单元/集成测试中用Mockito模拟Repo行为,强制抛出异常验证重试逻辑,示例:
@SpringBootTest @EnableRetry class DemoServiceTest { @MockBean private DemoRepo demoRepo; @Autowired private DemoService demoService; @Test void testSaveRetry() { // 模拟前两次抛异常,第三次返回成功结果 when(demoRepo.save(any(Demo.class))) .thenThrow(new SQLException("Mock DB error")) .thenThrow(new SQLException("Mock DB error")) .thenReturn(new Demo()); Demo result = demoService.save(new Demo()); // 验证save方法被调用3次 verify(demoRepo, times(3)).save(any(Demo.class)); assertNotNull(result); } } - 自定义AOP切面注入异常:编写Spring AOP切面,在
DemoRepo.save方法执行时手动抛出SQLException,通过开关控制是否触发,灵活测试重试逻辑。 - 数据库主动触发故障:用MySQL的
KILL CONNECTION命令,在测试时主动断开当前连接,模拟数据库异常;或借助Testcontainers启动临时数据库容器,通过网络工具模拟网络中断。
内容的提问来源于stack exchange,提问作者Rashmi Sharma
相关产品推荐
相关产品推荐

