Jenkins EC2 Spot实例中断后无法稳定重试问题排查
Jenkins EC2 Spot实例中断后重试不稳定问题排查与修复
问题场景
- 基于Jenkins Amazon EC2插件,将CI测试任务部署在EC2 Spot实例上,通过Pipeline脚本实现多节点并行执行
- 多数情况下,Spot实例被AWS中断后,任务能自动重试并切换到EC2 On-Demand实例;但偶尔会出现重试不触发的情况,且无明确失败日志
- 差异现象:成功触发重试的节点,构建页会显示“Agent was removed”消息,日志中存在
Could not connect to EC2 (ec2-spot) - Jenkins Agent Image (...) to send interrupt signal to process记录;未触发重试的节点无上述两项信息
根因分析
Jenkins的node块默认仅在代理主动断开连接或任务执行抛出明确异常时,才会触发外层的retry逻辑。但Spot实例被AWS强制终止时,部分场景下属于“静默断开”——实例直接被销毁,没有向Jenkins发送断开通知,导致Jenkins无法及时检测到代理状态异常,node块不会抛出异常,最终retry逻辑不生效。
而出现“无法连接代理发送中断信号”日志的场景,是Jenkins在尝试与代理通信时发现连接失败,才会判定节点异常并触发重试;无该日志的场景下,Jenkins尚未检测到代理断开,任务处于无响应状态,不会触发重试。
解决方案
1. 给任务添加主动健康检查,及时发现代理断开
在node块的测试阶段加入周期性健康检查,主动验证代理是否存活,避免任务无响应:
node(nodeLabel) { stage('Debug info') { // 原有调试逻辑 } stage('Run tests') { // 并行执行健康检查与测试任务,不阻塞测试流程 parallel( test: { // 原有测试执行逻辑 // ... }, healthCheck: { timeout(time: 85, unit: 'MINUTES') { while (true) { // 通过执行简单命令确认代理连接正常 sh 'echo "Agent health check: $(date)"' sleep(time: 3, unit: 'MINUTES') } } } ) } }
当代理断开时,健康检查的sh命令会抛出异常,触发外层的重试逻辑。
2. 强制捕获异常,确保重试逻辑触发
使用catchError包裹node块,将所有未捕获的异常(包括代理断开导致的隐性失败)标记为构建失败,确保retry能被触发:
retry(2) { timeout(time: 90, unit: 'MINUTES') { int retryCount = env["NODE_${index}_RETRY_COUNT"] nodeLabel = (retryCount == 0) ? "ec2-spot" : "ec2-on-demand" env["NODE_${index}_RETRY_COUNT"] = retryCount + 1 // 强制将所有异常标记为失败,触发重试 catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { node(nodeLabel) { stage('Debug info') { // ... } stage('Run tests') { // ... 健康检查+测试逻辑 } } } } }
3. 调整EC2插件配置,优化代理状态检测
在Jenkins的EC2插件全局配置中修改以下参数:
- 缩短代理连接超时时间:将默认的300秒调整为60秒,加快Jenkins对代理断开的感知速度
- 开启定期代理状态检查:设置每2分钟检查一次代理在线状态,及时发现静默断开的节点
- 启用实例终止自动标记离线:开启后,当AWS发送Spot实例终止通知时,插件会立刻将对应Jenkins节点标记为离线,触发任务失败重试
4. 优化重试计数存储,避免并行干扰
原脚本使用env存储重试计数,env在并行任务中存在共享风险,改用局部变量存储计数:
nodes[nodeDisplayName] = { script { int retryCount = 0 retry(2) { timeout(time: 90, unit: 'MINUTES') { nodeLabel = (retryCount == 0) ? "ec2-spot" : "ec2-on-demand" retryCount++ catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { node(nodeLabel) { // ... 原有逻辑 } } } } } }
总结
通过主动健康检查及时发现代理异常、强制捕获异常触发重试、调整插件配置优化状态检测这三个核心方向,即可解决Spot实例中断后重试不稳定的问题。
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

