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

Jenkins流水线用StreamingTemplateEngine遇NotSerializableException,加@NonCPS仍报错

解决Jenkins流水线中StreamingTemplateEngine的NotSerializableException问题

我之前也踩过这个一模一样的坑!Jenkins流水线的CPS序列化机制对非序列化对象特别敏感,哪怕加了@NonCPS注解,要是没把所有相关操作彻底隔离,还是会触发这个错误。

问题根源

Jenkins流水线会序列化整个执行上下文来支持暂停、恢复和分布式执行,而groovy.text.StreamingTemplateEngine本身是不可序列化的。哪怕你给函数加了@NonCPS,如果有部分和引擎相关的操作(比如创建模板对象、绑定变量)泄露到了CPS代码路径里,序列化检查还是会抓到它。

正确的解决方案

要把所有和StreamingTemplateEngine相关的逻辑完全封装在@NonCPS函数里,确保这个函数的返回值是可序列化的类型(比如String、基本数据类型),绝对不能让引擎对象或者模板对象逃出这个函数。

完整示例代码

pipeline {
    agent any
    stages {
        stage('Render Template & Run Script') {
            steps {
                script {
                    // 模板内容和绑定变量都用可序列化的类型
                    def templateContent = '''
                        echo "Hello, ${username}! Build number: ${buildNum}"
                    '''
                    def templateBindings = [
                        username: env.BUILD_USER,
                        buildNum: env.BUILD_NUMBER
                    ]
                    
                    // 调用@NonCPS函数拿到渲染后的字符串
                    def renderedScript = renderTemplate(templateContent, templateBindings)
                    
                    // 直接用渲染好的字符串执行sh步骤
                    sh renderedScript
                }
            }
        }
    }
}

// 所有模板相关操作都在这里,完全隔离CPS上下文
@NonCPS
def renderTemplate(String templateStr, Map bindings) {
    def engine = new groovy.text.StreamingTemplateEngine()
    def template = engine.createTemplate(templateStr)
    // 把渲染结果转为String返回,确保是可序列化的
    return template.make(bindings).toString().trim()
}

关键注意事项

  • 不要在@NonCPS函数之外创建StreamingTemplateEngine或模板对象,哪怕是临时变量也不行。
  • @NonCPS函数的返回值必须是可序列化的,比如上面的示例中返回的是String,而不是模板实例。
  • 如果你的模板内容需要动态生成,那生成模板内容的逻辑也最好放进@NonCPS函数里,避免引入其他非序列化对象。

内容的提问来源于stack exchange,提问作者Oron Bortman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:07:27