即使使用@NonCPS,Jenkins管道java.io.NotSerializableException java.util.regex.Matcher也会出错

Dan*_*ark 24 jenkins jenkins-pipeline

@NonCPS在我的Jenkinsfile函数前面使用它执行正则表达式匹配,java.io.NotSerializableException java.util.regex.Matcher即使使用@NonCPS注释我仍然会收到错误.

注意,它多次调用该函数,只有在实际匹配时才会发生异常.

这是我的代码:

@NonCPS
def extractEndTime(logLine) {
    def MY_REGEX = /.*(20[0-9]{2}-[0-9]{2}-[0-9]{2}).([0-9]{2}:[0-9]{2}:[0-9]{2}).*\"\w+\"\sthe text\s(\w+)\./
    m = (logLine =~ TEST_LOGLINE_END_REGEX)
    if (m.count) {
        return [m[1],m[2],m[3]]
    } else {
        return null
    }
}
Run Code Online (Sandbox Code Playgroud)

进行jenkins构建时的输出:

GitHub has been notified of this commit’s build result
java.io.NotSerializableException: java.util.regex.Matcher
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at java.util.LinkedHashMap.internalWriteEntries(LinkedHashMap.java:333)
    at java.util.HashMap.writeObject(HashMap.java:1354)
    at sun.reflect.GeneratedMethodAccessor116.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at com.cloudbees.groovy.cps.SerializableScript.writeObject(SerializableScript.java:26)
    at sun.reflect.GeneratedMethodAccessor145.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
    at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
    at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
    at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at java.util.HashMap.internalWriteEntries(HashMap.java:1777)
    at java.util.HashMap.writeObject(HashMap.java:1354)
    at sun.reflect.GeneratedMethodAccessor116.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
    at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)
    at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
    at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.writeObject(RiverWriter.java:132)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:433)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:412)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:357)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:78)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:236)
    at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:224)
    at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:63)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
    at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: an exception which occurred:
    in field delegate
    in field closures
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@42b37962
Finished: FAILURE
Run Code Online (Sandbox Code Playgroud)

izz*_*kil 31

可能由于m范围可变.尝试使用以下方式限制它def:

def m = (logLine =~ TEST_LOGLINE_END_REGEX)
Run Code Online (Sandbox Code Playgroud)

没有def变量是在全局脚本绑定中创建的,因此在退出方法后仍然存在.

  • 我不认为范围是这里的问题,因为 Jenkins 希望管道是可序列化的,并且抛出 `java.io.NotSerializableException: java.util.regex.Matcher` 异常是因为管道试图保存 a 的状态不可序列化的变量。看我下面的回答。 (4认同)
  • 我已经在使用 `def`,但我收到了这个错误。到目前为止未能理解导致此错误的原因。:( (3认同)
  • 我上面其实做了一个错误的结论。`Matcher.group()` 调用不是问题,而是使用提取字段的下一行,即使它是一个简单的回声,如 `echo "g1=${g1} g2=${g2}"`。由于 `g1` 和 `g2` 是没有引用 `Matcher` 的简单字符串,这没有任何意义,但这并不是我第一次在 Jenkins 管道中看到无法解释的错误。解决方法是将使用`Matcher` 的代码推送到一个函数中并从中返回组。尽管我没有将其声明为“NonCPS”,但这解决了问题。 (2认同)
  • 很惊讶这个答案被问题所有者接受并被这么多人点赞。这个答案根本不能解决问题。就像@SINGULARITY评论的那样,原因是Matcher不可序列化。我真的被这个答案误导了。我建议问题所有者删除接受标记并否决此答案。 (2认同)

SIN*_*ITY 26

Jenkins要求所有变量都是可序列化的,因为在服务器重启等中断的情况下,管道状态会定期保存到磁盘.此功能允许管道维持其状态,并在服务器重新启动后继续.Matcher类型的变量不可序列化,需要开发人员进行一些额外的工作.

来自jenkinsci/pipeline-plugin序列化局部变量:

然而,最安全的方法是在标记为@NonCPS的方法中隔离非可序列化状态的使用.这种方法将被Pipeline引擎视为"本机",其局部变量从未保存.

代码示例提供:

@NonCPS
def version(text) {
  def matcher = text =~ '<version>(.+)</version>'
  matcher ? matcher[0][1] : null
}
Run Code Online (Sandbox Code Playgroud)

支持这一点的其他材料可以在Pipeline Groovy插件技术设计中找到,在这里他们讨论更多技术细节和标记方法的行为@NonCPS.

管道脚本可以使用注释@NonCPS标记指定的方法.然后正常编译它们(沙盒安全检查除外),因此表现得非常像Java平台,Groovy运行时或Jenkins核心或插件代码中的"二进制"方法.@NonCPS方法可以安全地使用非Serializable对象作为局部变量,但它们不应接受不可序列化的参数或返回或存储不可序列化的值.您可能无法从@NonCPS方法调用常规(CPS转换)方法或管道步骤,因此它们最好用于在将摘要传递回主脚本之前执行某些计算.请特别注意,在二进制类中定义的方法的@Overrides,例如Object.toString(),通常应标记为@NonCPS,因为它通常是调用它们的二进制代码.

请参阅:序列化局部变量管道Groovy插件技术设计


小智 12

最近遇到这个。避免这种情况的一种方法是在将需要的部分提取到可序列化类型后,简单地将本地匹配器对象设置为 null。在执行其他步骤/操作之前,请确保它为空。

script {
    def label = 'v1.2.3'  // From git describe etc.
    def regex = '^v([0-9]+).([0-9]+).([0-9]+)$'
    def matcher = label =~ regex

    if (matcher) {
        def tag = matcher[0][0]
        def maj = matcher[0][1] as int
        def min = matcher[0][2] as int
        def patch = matcher[0][3] as int

        matcher = null
        echo "Found ${maj} ${min} ${patch} from ${tag}"
        // Additional steps
    } else {
        matcher = null
        echo "Nothing found"
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 5

为了清楚起见,以下内容对我有用。

开发人员的额外工作,例如,请参见下面的代码。

my.Parameter 不可序列化

所以我做了一个方法,没有 def 并注释它 @NonCPS 并从节点块调用它

  node('MySys') {
    echo 'hello'
    avoidCPS()
    echo 'finished'
  }

  @NonCPS
  avoidCPS () {
    // use my.Parameter here
    my.Parameter p = new my.Parameter()
    ... do some more ...
  }
Run Code Online (Sandbox Code Playgroud)


小智 5

以下工作(注意[0]):

def m = (it =~ /abcd/)[0]
Run Code Online (Sandbox Code Playgroud)

但这会导致java.io.NotSerializableException

def m = (it =~ /abcd/)
Run Code Online (Sandbox Code Playgroud)