无法通过詹金斯脚本管道中的NotSerializableException

时间:2020-08-18 05:38:48

标签: jenkins jenkins-pipeline jenkins-groovy

我有一个管道作业,该管道作业运行以下groovy脚本,但是一旦jenkins看到带有sh命令的行,就会引发以下异常。即使使用@NonCPS注释了该方法,我似乎也无法摆脱这种异常。 我想念什么?

node {
    stage('Kill Long Running jobs') {
        try {
            def longRunningJobs = getLongRunningJobs()
            if (longRunningJobs.size() > 0) {
                def metricData = killAndGetMetricData(longRunningJobs)
                if (metricData.size() > 0) {
                    def payload = metricData.join('\n')
                    sh("curl -X POST ${ENDPOINT} --data-binary ${payload}")
                }
            } else {
                echo 'No long running jobs'
            }
        } catch (err) {
            throw err
        }
    }
}

@NonCPS
def getLongRunningJobs() {
    def timeInMillis = 24*3600*1000
    def rightNow = Calendar.getInstance()
    return Jenkins.instance.getAllItems(Job.class).findAll { Job job ->
        job.isBuilding()
    }.collect { Job job ->
        //find all matching items and return a list but if null then return an empty list
        job.builds.findAll { Run run ->
            run.isBuilding() && ((rightNow.getTimeInMillis() - run.getStartTimeInMillis()) > timeInMillis)
        } ?: []
    }.sum()
}

错误:

an exception which occurred:
    in field com.cloudbees.groovy.cps.impl.BlockScopeEnv.locals
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@5dc513b2
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@788991c6
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@76c7fb80
    in field com.cloudbees.groovy.cps.impl.CallEnv.caller
    in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@41b11dd6
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@4a0dec81
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@21e5f4ba
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.TryBlockEnv@69fbc75f
    in field com.cloudbees.groovy.cps.impl.ProxyEnv.parent
    in object com.cloudbees.groovy.cps.impl.BlockScopeEnv@430907d9
    in field com.cloudbees.groovy.cps.impl.CallEnv.caller
    in object com.cloudbees.groovy.cps.impl.FunctionCallEnv@779bb867
    in field com.cloudbees.groovy.cps.Continuable.e
    in object org.jenkinsci.plugins.workflow.cps.SandboxContinuable@e363a3
    in field org.jenkinsci.plugins.workflow.cps.CpsThread.program
    in object org.jenkinsci.plugins.workflow.cps.CpsThread@29a42aee
    in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.threads
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@23c20513
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@23c20513
Caused: java.io.NotSerializableException: org.jenkinsci.plugins.workflow.job.WorkflowRun
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:926)

1 个答案:

答案 0 :(得分:0)

您真的不应该将沉重的内部Jenkins对象(例如“工作”)泄漏到管道的CPS部分中。由于Jenkins的管道作业类型需要能够随时挂起和恢复管道,因此管道中的所有对象都需要可序列化-大多数内部Jenkins对象在设计时就没有考虑到这一点。

如果您真的需要在管道中使用Jenkins内部对象,请将所有内容包装到@NonCPS方法中。根据经验:在管道CPS代码中只能使用“简单”对象,例如String或List。对于上面的代码,我建议:

  • 要么返回getLongRunningJobs()的字符串列表(工作名称?),然后修改killAndGetMetricData()以获取字符串列表
  • 或者(可能更容易)重构您的代码以结合使用这两种方法,并且仅返回字符串列表(甚至仅返回有效载荷字符串)

有关更多技术细节,请参见https://www.jenkins.io/blog/2017/02/01/pipeline-scalability-best-practice/