tutorial plugin example español jenkins-workflow jenkins-pipeline jenkinsfile

jenkins-workflow - plugin - pipeline jenkins español



¿Cómo evito que dos trabajos jenkins de canalización del mismo tipo se ejecuten en paralelo en el mismo nodo? (10)

No quiero permitir que dos trabajos del mismo tipo (mismo repositorio) no se ejecuten en paralelo en el mismo nodo.

¿Cómo puedo hacer esto usando groovy dentro de Jenkinsfile?


Creo que hay más de un enfoque para este problema.

Tubería

Jenkins

  • ¿Limitar el número de ejecutores del nodo a 1 ?

Complementos


Ejemplo usando el bloque de opciones en la sintaxis de canalización declarativa:

pipeline { options { disableConcurrentBuilds() } ... }


El " Complemento de compilaciones concurrentes del acelerador " ahora es compatible con la canalización desde throttle-concurrents-2.0 . Entonces ahora puedes hacer algo como esto:

// 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'') }

Desde la vista de la etapa de canalización, podrá apreciar esto:

Sin embargo, tenga en cuenta que esto solo funciona para bloques de node dentro throttle bloque del throttle . Tengo otras tuberías donde primero asigno un nodo, luego hago un trabajo que no necesita aceleración y luego otro que sí.

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

En este caso, el paso del throttle no resuelve el problema porque el paso del throttle es el que está dentro del paso del node y no al revés. En este caso, el paso de bloqueo es más adecuado para la tarea


Hasta que el complemento "Throttle Concurrent Builds" tenga soporte para Pipeline , una solución sería ejecutar efectivamente un ejecutor del master con una etiqueta que requiera su trabajo.

Para hacer esto, cree un nuevo nodo en Jenkins, por ejemplo, un nodo SSH que se conecte a localhost. También puede usar la opción de comando para ejecutar slave.jar / swarm.jar dependiendo de su configuración. Dale al nodo un ejecutor y una etiqueta como "resource-foo", y dale a tu trabajo esta etiqueta también. Ahora solo se puede ejecutar un trabajo de etiqueta "resource-foo" a la vez porque solo hay un ejecutor con esa etiqueta. Si configura el nodo para que esté en uso tanto como sea posible (predeterminado) y reduce el número de ejecutores maestros en uno, debería comportarse exactamente como se desea sin un cambio en el total de ejecutores.



La respuesta proporcionada en https://.com/a/43963315/6839445 está en desuso.

El método actual para deshabilitar compilaciones concurrentes es establecer opciones:

options { disableConcurrentBuilds() }

La descripción detallada está disponible aquí: https://jenkins.io/doc/book/pipeline/syntax/#options


Otra forma es usar el complemento de recursos bloqueables: https://wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin

Puede definir bloqueos (mutexes) como desee y puede poner variables en los nombres. Por ejemplo, para evitar que varios trabajos utilicen un compilador al mismo tiempo en un nodo de compilación:

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

Entonces, si desea evitar que más de un trabajo de la misma rama se ejecute simultáneamente por nodo, puede hacer algo como

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

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


Si eres como mi equipo, entonces te gusta tener Jenkins Jobs parametrizados y fáciles de usar que los scripts de canalización se disparan en etapas, en lugar de mantener toda esa sopa declarativa / maravillosa. Desafortunadamente, eso significa que cada construcción de canalización ocupa más de 2 ranuras de ejecución (una para el script de canalización y otras para los trabajos activados), por lo que el peligro de punto muerto se vuelve muy real.

He buscado soluciones para ese dilema en todas partes y deshabilitarConcurrentBuilds () solo evita que el mismo trabajo (rama) se ejecute dos veces. No hará que las compilaciones de canalizaciones para diferentes ramas se pongan en cola y esperen en lugar de ocupar preciosos espacios de ejecutor.

Una solución hacky (pero sorprendentemente elegante) para nosotros fue limitar los ejecutores del nodo maestro a 1 y hacer que las secuencias de comandos de la tubería se apeguen a usarlo (y solo a él), luego conectar un agente esclavo local a Jenkins para encargarse de todo otros trabajos.


Tienes en la propiedad disableConcurrentBuilds:

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

Entonces el trabajo esperaría que el mayor terminara primero


Una de las opciones es usar Jenkins REST API. Investigué otras opciones, pero parece que esta solo está disponible con la funcionalidad de canalización.

Debería escribir un script que sondee a Jenkins para obtener información de los trabajos actuales en ejecución y verificar si se está ejecutando un trabajo del mismo tipo. Para hacer esto, debe utilizar la API REST de Jenkins, documentación que puede encontrar en la esquina inferior derecha de su página de Jenkins. Script de ejemplo:

#!/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."

He usado bash aquí, pero puedes usar cualquier idioma. Luego simplemente llame a este script dentro de su Jenkinsfile:

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

Por lo tanto, esperará hasta la finalización del trabajo (no se confunda con las menciones de prueba de integración, es solo el nombre del trabajo).

También tenga en cuenta que, en casos excepcionales, este script puede causar un punto muerto cuando ambos trabajos se esperan el uno al otro, por lo que es posible que desee implementar algunas políticas de reintento máximo aquí en lugar de una espera infinita.