jenkins 并行工作流插件失败 java.io.NotSerializableException:hudson.plugins.sshslaves.SSHLauncher

jenkins parallel workflow plugin fails with java.io.NotSerializableException: hudson.plugins.sshslaves.SSHLauncher

为什么 parallel 会为如此简单的事情抛出序列化错误的任何线索:

  branches[nodeSpec] = {
      node(nodeSpec) {
        echo("remote");
      }

我正在尝试编写一个工作流插件构建来在我的所有节点上执行维护任务。这在今天早些时候有效,即使我执行该代码,我也会遇到以下失败。我不明白是什么导致了这个问题。我知道这可能是变量使用的问题,但我认为我没有在我的节点闭包中使用任何变量。

如果您有任何建议,请告诉我

错误

java.io.NotSerializableException: hudson.plugins.sshslaves.SSHLauncher at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860) 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.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65) at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)

代码

// Get all Nodes from Jenkins instance
def nodelist = Jenkins.getInstance().getNodes()
branches = [:]

// Iterate list -- NOTE: we cannot use groovy style or even modern java style iteration
for (int i =0; i < nodelist.size(); i++) {
   Slave node = nodelist[i]
   def nodeSpec =  node.name.toString()
   if (node.getComputer().isOnline()) {  
      println "Create Task for ${nodeSpec}"
      branches[nodeSpec] = {
          node(nodeSpec) {
            echo("remote");
          }

      }
   }
 }  

parallel branches

更新: 从下面的评论中我发现我误解了 NonCPS 注释的要求。如果在分支内使用该方法,这对于防止问题是必要的,并且即使在分支执行之前使用该方法也是为了清晰起见的好主意。

我有工作代码和理论来解释它为什么有效。

  • 隔离 Jenkins 从对象以确保它们不会被传送到节点,因为它们无法被序列化。 (getOnlineNodeNames 将局部变量呈现为字符串列表)
  • 将条件语句移出节点(不确定为什么会产生任何影响)

代码

@NonCPS
List <String> getOnlineNodeNames() {
  List <String> nodeNames = []
  def allNodes = Jenkins.getInstance().getNodes()
  for (int i =0; i < allNodes.size(); i++) {
   Slave node = allNodes[i]

   if (node.getComputer().isOnline()) {  
    nodeNames.add(node.name.toString())
   }
  }
  return nodeNames
}


List<String> nodeList = getOnlineNodeNames()

branches = [:]
for (int i =0; i < nodeList.size(); i++) {
  String nodeName = nodeList[i]
  if(nodeName.contains("win")) {
    branches[nodeName] = { node(nodeName) { 
             bat '''@echo off
DoMainTasks....'''

       } 
    }
  } else {
    branches[nodeName] = { node(nodeName) { 
         sh '''set +x
DoMainTasks....'''
       } 
    }
  }

}
parallel branches