Подтвердить что ты не робот

Как предотвратить параллельное выполнение двух проектов jenkins для одного и того же типа в одном и том же node?

Я не хочу, чтобы два задания того же типа (один и тот же репозиторий) не выполнялись параллельно на одном и том же node.

Как это сделать, используя groovy внутри Jenkinsfile?

4b9b3361

Ответ 1

Вы получили свойство disableConcurrentBuilds:

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

Затем задание будет ждать старшего, чтобы закончить первый

Ответ 2

Другой способ - использовать плагин Lockable Resources: https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin

Вы можете определить блокировки (мьютексы), но вы хотите, и можете помещать переменные в имена. Например. для предотвращения одновременного использования несколькими заданиями компилятора в сборке node:

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

Итак, если вы хотите предотвратить более одного задания одной ветки, выполняемой одновременно за node, вы можете сделать что-то вроде

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/

Ответ 4

Я думаю, что существует более чем один подход к этой проблеме.

Трубопроводный

  • Используйте последнюю версию Lockable Resources Plugin и ее шаг lock, как это предлагается в другом ответе.
  • Если вы строите один и тот же проект:
    • Снимите флажок Execute concurrent builds if necessary.
  • Если вы строите разные проекты:
    • Задайте разные node или label для каждого проекта.

Дженкинс

  • Ограничить число исполнителей node до 1?

Плагины

Ответ 5

" Плагин Throttle Concurrent Builds " теперь поддерживает конвейер начиная с 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 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 а не наоборот. В этом случае шаг блокировки лучше подходит для задачи

Ответ 6

Пример использования блока параметров в синтаксисе декларативного конвейера:

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}

Ответ 7

Установите Jenkins Заблокированный плагин ресурсов.

В вашем конвейере script завершите часть блокировки и дайте этому заблокированному ресурсу имя.

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

Используйте имя любого ресурса, который вы блокируете. По моему опыту, это обычно тестовый сервер или тестовая база данных.

Ответ 8

Один из вариантов - использовать JENKSIS REST API. Я исследовал другие варианты, но кажется, что это только один доступный с функциями конвейеров.

Вам следует написать script, который опросит Jenkins для получения информации о текущих заданиях и проверяет, работает ли работа того же типа. Для этого вы должны использовать Jenkins REST API, документацию, которую вы можете найти в правом нижнем углу на странице Jenkins. Пример script:

#!/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 здесь, но вы можете использовать любой язык. Затем просто вызовите этот script внутри вашего файла Jenkins:

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

Таким образом, он будет ждать завершения задания (не путайте с тегами интеграции-теста, это просто имя задания).

Также помните, что в редких случаях это script может вызвать тупик, когда оба задания ждут друг друга, поэтому вы можете реализовать здесь несколько стратегий повторной проверки, а не бесконечное ожидание.

Ответ 9

До тех пор, пока плагин "Throttle Concurrent Builds" не имеет поддержки Pipeline, решением было бы эффективно запустить одного исполнителя мастера с меткой, которая ваша работа требует.

Для этого создайте новый node в Jenkins, например SSH node, который подключается к localhost. Вы также можете использовать параметр команды для запуска slave.jar/swarm.jar в зависимости от вашей установки. Дайте node одному исполнителю и ярлыку, например "resource-foo", и дайте вашей работе этот ярлык. Теперь только одно задание метки "resource-foo" может запускаться за раз, потому что есть только один исполнитель с этой записью. Если вы установите как можно больше (w630) node (по умолчанию) и уменьшите количество мастер-исполнителей на единицу, он должен вести себя точно так, как требуется, без изменений для полных исполнителей.

Ответ 10

Если вы похожи на мою команду, то вам нравится иметь удобные в использовании параметризованные задания Дженкинса, которые конвейерные сценарии запускают поэтапно, вместо того, чтобы поддерживать весь этот декларативный/идеальный суп. К сожалению, это означает, что каждая сборка конвейера занимает слоты исполнителя 2+ (один для сценария конвейера, а другие для запускаемых заданий), поэтому опасность тупика становится очень реальной.

Я всюду искал решения этой дилеммы, а disableConcurrentBuilds() не позволяет дважды запускать одно и то же задание (ветвь). Это не заставит конвейерные сборки для разных веток стоять в очереди и ждать вместо того, чтобы занимать драгоценные слоты исполнителя.

Хакерское (но удивительно элегантное) решение для нас заключалось в том, чтобы ограничить количество исполнителей главного узла 1 и заставить конвейерные сценарии придерживаться его (и только его), а затем подключить локального подчиненного агента к Дженкинсу, чтобы позаботиться обо всех другие работы.