Jenkins管道脚本-线程编程

oxosxuxt  于 2023-04-29  发布在  Jenkins
关注(0)|答案(3)|浏览(167)

我试图在jenkins管道脚本中创建多个线程。所以,我举了一个简单的例子如下。但它不起作用。你能告诉我吗?
在下面的示例中,jobMap包含字符串形式的键和字符串列表形式的值。当我只是显示列表时,值打印正确,但当我使用3种不同的方法来创建线程并显示时,它不起作用。

for ( item in jobMap ) 
    {           
        def jobList = jobMap.get(item.key);

        **// The following loop is printing the values**
        for (jobb in jobList) 
        {
                 echo "${jobb}"
        }

//线程实现1:

Thread.start 
        {

                for (jobb in jobList) 
                {
                 echo "${jobb}"
                }

        }

//线程实现2:

def t = new Thread({ echo 'hello' } as Runnable)
        t.start() ;
        t.join();

//线程实现3:

t1 = new Thread( new TestMultiThreadSleep(jobList));
        t1.start();         
    }


    class TestMultiThreadSleep implements Runnable {
   String jobs;
   public TestMultiThreadSleep(List jobs) {
      this.jobs = jobs;
   }


     @Override
       public void run() 
{
       echo "coming here"
         for (jobb in jobs) 
            {
                 echo "${jobb}"
            }                      
       }
    }
jjhzyzn0

jjhzyzn01#

Jenkins有一个特殊的步骤-parallel()。在此步骤中,您可以构建其他作业或调用Pipeline代码。

vptzau2j

vptzau2j2#

最好将Pipeline代码视为Groovy的方言或子集。
工作流脚本引擎中的CPS转换器(“continuation-passing style”)将Groovy代码转换为可以以序列化形式解释、在不同JVM之间传递等的内容。
您可能会想到,这对于线程根本不起作用。
如果你需要线程,你必须在一个@NonCPS注解的类或函数中工作。这个类或函数不能调用任何CPS groovy代码--因此它不能调用闭包、访问工作流脚本上下文等。
这就是为什么使用parallel步骤更可取。

k3fezbri

k3fezbri3#

对于您的场景,您应该只使用parallel块。现在,如果您真的需要让一个worker在后台运行Jenkinsfile(E.例如,尝试读取streaming REST端点),请继续阅读此答案。
我不是100%意识到这种方法的复杂性,但我认为我找到了一种方法来启动线程并在Jenkinsfile中监视它们的进度from a CPS block(类似于脚本块)。

***1.写一个TestMultiThreadSleep类***修改为在非CPS上下文中。

class TestMultiThreadSleep implements Runnable {
  private def jobs
  private def processedJobs
  private def finished = false

  public TestMultiThreadSleep(List jobs) {
    this.jobs = jobs;
  }

  @NonCPS
  def getProcessedJobs() {
    processedJobs
  }

  @NonCPS
  def isFinished() {
    finished
  }

  @NonCPS
  void run() {
    for (jobb in jobs) {
      // process what ever you want and 
      // populate the memeber processedJobs with the output.
      // You can not use any Jenkinsfile DSL method.
    }
    finished = true                    
  }
}

***2.将runnable提交给executionService***此方法将使runnable在非CPS上下文中运行。据我所知,即使你不显式调用executor.shutDown()方法,submit方法也会示例化一个FinalizableDelegatedExecutorService对象。这是一个应该安全地关闭引擎盖下线程的委托。

import java.util.concurrent.Executors

@NonCPS
void submitWorker(worker) {
  def executor = Executors.newSingleThreadExecutor()
  executor.submit(worker)
}

***3.从CPS上下文提交可运行的文件并编写一个等待块***这种监控方式非常重要,我发现jenkins管道超时不适用于nonCPS wait periods,这些时间段对于Jenkins来说被认为是相当的时间段,无论您设置的超时选项如何,它默认为5分钟。

...
script {
  def runnable = new TestMultiThreadSleep(jobList)
  submit(runnable)
  
  int elapsedSecs = 0
  int timeout = 40
  while(!runnable.isFinished() && elapsedSecs <= timeout) {
    sleep(1)
    elapsedSecs++
  }
}
...

相关问题