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
相关产品推荐
相关产品推荐

