Я не хочу, чтобы два задания того же типа (один и тот же репозиторий) не выполнялись параллельно на одном и том же node.
Как это сделать, используя groovy внутри Jenkinsfile?
Я не хочу, чтобы два задания того же типа (один и тот же репозиторий) не выполнялись параллельно на одном и том же node.
Как это сделать, используя groovy внутри Jenkinsfile?
Вы получили свойство disableConcurrentBuilds:
properties properties: [
...
disableConcurrentBuilds(),
...
]
Затем задание будет ждать старшего, чтобы закончить первый
Другой способ - использовать плагин 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/
Ответ на fooobar.com/questions/252142/... устарел.
Текущий метод для отключения одновременных сборок состоит в том, чтобы установить параметры:
options { disableConcurrentBuilds() }
Подробное описание доступно здесь: https://jenkins.io/doc/book/pipeline/syntax/#options
Я думаю, что существует более чем один подход к этой проблеме.
lock
, как это предлагается в другом ответе.Execute concurrent builds if necessary
.node
или label
для каждого проекта.1
? " Плагин 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')
}
С точки зрения конвейера вы сможете оценить это:
Однако имейте в виду, что это работает только для 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
а не наоборот. В этом случае шаг блокировки лучше подходит для задачи
Пример использования блока параметров в синтаксисе декларативного конвейера:
pipeline {
options {
disableConcurrentBuilds()
}
...
}
Установите Jenkins Заблокированный плагин ресурсов.
В вашем конвейере script завершите часть блокировки и дайте этому заблокированному ресурсу имя.
lock("test-server"){
// your steps here
}
Используйте имя любого ресурса, который вы блокируете. По моему опыту, это обычно тестовый сервер или тестовая база данных.
Один из вариантов - использовать 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 может вызвать тупик, когда оба задания ждут друг друга, поэтому вы можете реализовать здесь несколько стратегий повторной проверки, а не бесконечное ожидание.
До тех пор, пока плагин "Throttle Concurrent Builds" не имеет поддержки Pipeline, решением было бы эффективно запустить одного исполнителя мастера с меткой, которая ваша работа требует.
Для этого создайте новый node в Jenkins, например SSH node, который подключается к localhost. Вы также можете использовать параметр команды для запуска slave.jar/swarm.jar в зависимости от вашей установки. Дайте node одному исполнителю и ярлыку, например "resource-foo", и дайте вашей работе этот ярлык. Теперь только одно задание метки "resource-foo" может запускаться за раз, потому что есть только один исполнитель с этой записью. Если вы установите как можно больше (w630) node (по умолчанию) и уменьшите количество мастер-исполнителей на единицу, он должен вести себя точно так, как требуется, без изменений для полных исполнителей.
Если вы похожи на мою команду, то вам нравится иметь удобные в использовании параметризованные задания Дженкинса, которые конвейерные сценарии запускают поэтапно, вместо того, чтобы поддерживать весь этот декларативный/идеальный суп. К сожалению, это означает, что каждая сборка конвейера занимает слоты исполнителя 2+ (один для сценария конвейера, а другие для запускаемых заданий), поэтому опасность тупика становится очень реальной.
Я всюду искал решения этой дилеммы, а disableConcurrentBuilds() не позволяет дважды запускать одно и то же задание (ветвь). Это не заставит конвейерные сборки для разных веток стоять в очереди и ждать вместо того, чтобы занимать драгоценные слоты исполнителя.
Хакерское (но удивительно элегантное) решение для нас заключалось в том, чтобы ограничить количество исполнителей главного узла 1 и заставить конвейерные сценарии придерживаться его (и только его), а затем подключить локального подчиненного агента к Дженкинсу, чтобы позаботиться обо всех другие работы.