如何防止同一类型的两个管道jenkins作业在同一节点上并行运行?

时间:2016-04-06 14:27:46

标签: jenkins-workflow jenkins-pipeline jenkinsfile

我希望不允许同一类型的两个作业(相同的存储库)不能在同一节点上并行运行。

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

10 个答案:

答案 0 :(得分:37)

你有了disableConcurrentBuilds属性:

def json_data(request):
    data = words.objects.all()
    return JsonResponse(list(data), safe=False)

然后该作业将等待较旧的作业完成

答案 1 :(得分:24)

另一种方法是使用Lockable Resources插件: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/

答案 2 :(得分:24)

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

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

options { disableConcurrentBuilds() }

详细说明如下: https://jenkins.io/doc/book/pipeline/syntax/#options

答案 3 :(得分:12)

我认为解决这个问题不仅仅是一种方法。

管道

  • 使用最新版本的Lockable Resources Plugin及其lock步骤,如其他答案所示。
  • 如果构建相同的项目:
    • 取消选中Execute concurrent builds if necessary
  • 如果建立不同的项目:
    • 为每个项目设置不同的nodelabel

詹金斯

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

插件

答案 4 :(得分:11)

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

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}

答案 5 :(得分:9)

" Throttle Concurrent Builds Plugin"现在支持自throttle-concurrents-2.0以来的管道。所以现在你可以这样做:

// Fire me twice, one immediately after the other
// by double-clicking 'Build Now' or from a parallel step in another job.
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')
}

从管道阶段视图中,您将能够理解这一点:

enter image description here

但是,请注意,这仅适用于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步骤中的步骤,而不是相反。在这种情况下,the lock step更适合任务

答案 6 :(得分:5)

安装Jenkins Lockable Resources Plugin

在您的管道脚本中,将部件包装在锁定块中,并为此可锁定资源命名。<​​/ p>

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

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

答案 7 :(得分:3)

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

我到处寻找解决这个难题的方法,而disableConcurrentBuilds()只能阻止同一个工作(分支)运行两次。它不会让不同分支的管道构建排队等待,而不是占用宝贵的执行器插槽。

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

答案 8 :(得分:2)

其中一个选项是使用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}"

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

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

答案 9 :(得分:1)

直到&#34; Throttle Concurrent Builds&#34;插件has Pipeline support,解决方案是使用您的工作所需的标签有效地运行主服务器的一个执行程序。

为此,请在Jenkins中创建一个新节点,例如连接到localhost的SSH节点。您还可以使用命令选项运行slave.jar / swarm.jar,具体取决于您的设置。给节点一个执行器和一个像#34; resource-foo&#34;这样的标签,并给你的工作这个标签。现在只有一份标签&#34; resource-foo&#34;可以一次运行,因为只有一个执行器与该标签。如果将节点设置为尽可能多地使用(默认)并将主执行程序的数量减少一个,则它应该完全按照需要运行,而不更改总执行程序。