85

我不想让相同类型(相同存储库)的两个作业在同一个节点上并行运行。

如何在 Jenkinsfile 中使用 groovy 来做到这一点?

4

10 回答 10

76

https://stackoverflow.com/a/43963315/6839445中提供的答案已弃用。

当前禁用并发构建的方法是设置选项:

options { disableConcurrentBuilds() }

详细说明可在此处获得: https ://jenkins.io/doc/book/pipeline/syntax/#options

于 2018-02-13T13:36:22.797 回答
47

你得到了 disableConcurrentBuilds 属性:

properties properties: [
  ...
  disableConcurrentBuilds(),
  ...
]

然后工作将等待较旧的先完成

于 2017-05-14T11:23:33.580 回答
34

另一种方法是使用可锁定资源插件:https ://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin

您可以根据需要定义锁(互斥体),并且可以将变量放入名称中。例如,防止多个作业在构建节点上同时使用编译器:

stage('Build') {
    lock(resource: "compiler_${env.NODE_NAME}", inversePrecedence: true) {
      milestone 1
      sh "fastlane build_release"
    }
}

因此,如果您想防止每个节点同时运行同一分支的多个作业,您可以执行类似的操作

stage('Build') {
    lock(resource: "lock_${env.NODE_NAME}_${env.BRANCH_NAME}", inversePrecedence: true) {
      milestone 1
      sh "fastlane build_release"
    }
}

来自:https ://www.quernus.co.uk/2016/10/19/lockable-resources-jenkins-pipeline-builds/

于 2016-10-23T16:48:31.800 回答
34

在声明性管道语法中使用选项块的示例:

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}
于 2018-02-15T10:49:05.197 回答
16

我认为解决这个问题的方法不止一种。

管道

  • 按照其他答案中的建议,使用最新版本的可锁定资源插件及其步骤。lock
  • 如果构建相同的项目:
    • 取消选中Execute concurrent builds if necessary
  • 如果构建不同的项目:
    • 为每个项目设置不同的node或。label

詹金斯

  • 将节点的执行者数量限制为1

插件

于 2016-04-07T21:33:31.760 回答
14

Throttle Concurrent Builds Plugin ”现在支持管道,因为throttle-concurrents-2.0. 所以现在你可以做这样的事情:

点燃下面的管道两次,一个紧接着另一个,你会看到。您可以通过双击“立即构建”parallel或从另一个作业中的步骤调用它来手动执行此操作。

stage('pre'){
    echo "I can run in parallel"
    sleep(time: 10, unit:'SECONDS')
}
throttle(['my-throttle-category']) {
    
    // Because only the node block is really throttled.
    echo "I can also run in parallel" 
    
    node('some-node-label') {
        
        echo "I can only run alone"
        
        stage('work') {
            
            echo "I also can only run alone"
            sleep(time: 10, unit:'SECONDS')
            
        }
    }
}
stage('post') {
    echo "I can run in parallel again"
    // Let's wait enough for the next execution to catch
    // up, just to illustrate.
    sleep(time: 20, unit:'SECONDS')
}

从管道阶段视图中,您将能够欣赏到这一点:

在此处输入图像描述

但是,请注意,这仅适用于node块内的throttle块。我确实有其他管道,我首先分配一个节点,然后做一些不需要节流的工作,然后做一些需要节流的工作。

node('some-node-label') {

    //do some concurrent work

    //This WILL NOT work.
    throttle(['my-throttle-category']) {
        //do some non-concurrent work
    }
}

在这种情况下,throttle步骤并不能解决问题,因为throttle步骤是步骤内部的node步骤,而不是相反的步骤。在这种情况下,锁定步骤更适合该任务

于 2017-06-13T11:04:04.073 回答
8

安装 Jenkins可锁定资源插件

在您的管道脚本中,将该部分包装在锁定块中,并为该可锁定资源命名。

lock("test-server"){
    // your steps here
}

使用您要锁定的任何资源的名称。以我的经验,它通常是一个测试服务器或测试数据库。

于 2016-12-09T14:43:27.733 回答
5

如果您像我的团队一样,那么您喜欢让管道脚本分阶段触发的用户友好的参数化 Jenkins 作业,而不是维护所有声明性/常规的汤。不幸的是,这意味着每个管道构建占用 2+ 个执行器插槽(一个用于管道脚本,另一个用于触发的作业),因此死锁的危险变得非常真实。

我到处寻找解决该困境的方法,并且disableConcurrentBuilds()只阻止同一个作业(分支)运行两次。它不会使不同分支的管道构建排队等待,而不是占用宝贵的执行器插槽。

对我们来说,一个 hacky(但令人惊讶的优雅)解决方案是将主节点的执行程序限制为 1,并使管道脚本坚持使用它(并且只使用它),然后将本地从代理连接到 Jenkins 以照顾所有其他工作。

于 2018-03-21T13:15:02.980 回答
4

一种选择是使用 Jenkins REST API。我研究了另一种选择,但似乎这只是一个具有管道功能的可用选项。

您应该编写脚本来轮询 Jenkins 以获取当前正在运行的作业的信息,并检查是否正在运行相同类型的作业。为此,您应该使用 Jenkins REST API,您可以在 Jenkins 页面的右下角找到文档。示例脚本:

#!/usr/bin/env bash

# this script waits for integration test build finish
# usage: ./wait-for-tests.sh <jenkins_user_id> <jenkins_user_token_id>
jenkins_user=$1
jenkins_token=$2
build_number=$3

job_name="integration-tests"
branch="develop"

previous_build_number=build_number
let previous_build_number-=1
previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')

while [ "$previous_job_status" == "null" ];
do
    previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')
    echo "Waiting for tests completion"
    sleep 10
done

echo "Seems that tests are finished."

我在这里使用过 bash,但您可以使用任何语言。然后只需在 Jenkinsfile 中调用此脚本:

sh "./wait-for-tests.sh ${env.REMOTE_USER} ${env.REMOTE_TOKEN} ${env.BUILD_NUMBER}"

所以它会等到工作完成(不要与集成测试提及混淆,它只是工作名称)。

另请注意,在极少数情况下,当两个作业相互等待时,此脚本可能会导致死锁,因此您可能希望在此处实施一些最大重试策略,而不是无限等待。

于 2016-07-08T12:06:18.490 回答
1

在“Throttle Concurrent Builds”插件支持 Pipeline之前,一个解决方案是使用您的工作所需的标签有效地运行 master 的一个 executor。

为此,请在 Jenkins 中创建一个新节点,例如连接到 localhost 的 SSH 节点。您还可以根据您的设置使用命令选项来运行 slave.jar/swarm.jar。给节点一个执行者和一个像“resource-foo”这样的标签,并给你的工作这个标签。现在一次只能运行一个标签为“resource-foo”的作业,因为只有一个带有该标签的执行者。如果您将节点设置为尽可能多地使用(默认)并将主执行器的数量减少一个,那么它的行为应该完全符合预期,而不会更改总执行器。

于 2016-09-07T17:55:17.647 回答