You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:01:20