jenkins parallel-processing closures jenkins-pipeline currying

jenkins - Currying Groovevy CPS closure para ejecución paralela



parallel-processing closures (3)

Encontré que con el último plugin de Pipeline: Groovy (2.40) combinado con al menos la versión 2.60.3 de Jenkins (aunque la página de inicio de plugins indica que se necesita al menos Jenkins 2.73.3) todo funciona como se esperaba.

Hacemos una creación dinámica de pasos paralelos en algunos de nuestros trabajos. Gracias a este hilo encontré cómo crear dinámicamente el mapa con parámetros para usar en el paso paralelo.

Sin embargo, ahora quería reutilizar partes del código que se usa para crear esos pasos paralelos. Por esto siento que tendría que curry los cierres.

Sin embargo, curry parece no funcionar correctamente. Hacer referencia a la variable de bucle (valueCopy) dentro del cierre hace lo correcto ( como se menciona aquí ) pero currying no hace lo que yo esperaría.

¿Estoy haciendo algo mal? ¿Esto no es (todavía) compatible? ¿Hay alguna solución alternativa? ¿Es esto probablemente un error en la tubería de Jenkins?

Espero que alguien tenga una idea de por qué esto no funciona y / o cómo hacerlo funcionar.

Jenkins: LTS (2.32.1) y las últimas actualizaciones de complementos a partir del 19/01/2017.

Script de tubería ejecutado:

def echoSome (val) {echo val}

def buildClosures() { def someList = ["1", "2", "3"] def closures = [:] for (value in someList) { final valueCopy = value closures[value] = {val -> echo valueCopy.toString() echo val.toString() }.curry(value) } closures } parallel buildClosures()

Salida:

[Pipeline] parallel [Pipeline] [1] { (Branch: 1) [Pipeline] [2] { (Branch: 2) [Pipeline] [3] { (Branch: 3) [Pipeline] [1] echo [1] 1 [Pipeline] [1] echo [1] 3 [Pipeline] [1] } [Pipeline] [2] echo [2] 2 [Pipeline] [2] echo [2] 3 [Pipeline] [2] } [Pipeline] [3] echo [3] 3 [Pipeline] [3] echo [3] 3 [Pipeline] [3] } [Pipeline] // parallel [Pipeline] End of Pipeline Finished: SUCCESS

Rendimiento esperado:

[Pipeline] parallel [Pipeline] [1] { (Branch: 1) [Pipeline] [2] { (Branch: 2) [Pipeline] [3] { (Branch: 3) [Pipeline] [1] echo [1] 1 [Pipeline] [1] echo [1] 1 [Pipeline] [1] } [Pipeline] [2] echo [2] 2 [Pipeline] [2] echo [2] 2 [Pipeline] [2] } [Pipeline] [3] echo [3] 3 [Pipeline] [3] echo [3] 3 [Pipeline] [3] } [Pipeline] // parallel [Pipeline] End of Pipeline Finished: SUCCESS


Esto parece ser una limitación tanto del lenguaje Groovy como del tiempo de ejecución maravilloso de Jenkins, no estoy seguro de cuál, pero vale la pena señalar que sus ejemplos hacen exactamente lo mismo que tú, declarando una nueva variable para cada iteración del ciclo.

Ellos han comentado su ejemplo

// nueva variable por iteración; seré mutado

No creo que el uso de bucles C-style elimine esta limitación y el currying (que sería necesario para este caso de uso) tampoco resuelve el problema. Torpe, pero lo suficientemente fácil como para evitarlo.

https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#creating-multiple-threads


No estoy seguro de si es el currying, o el ciclo for, pero esta función debe marcarse como NonCPS como se describe aquí: https://github.com/jenkinsci/pipeline-examples/blob/master/docs/BEST_PRACTICES. md # groovy-gotchas

Esencialmente, haz esto:

@NonCPS def buildClosures() { def someList = ["1", "2", "3"] def closures = [:] for (value in someList) { final valueCopy = value closures[value] = {val -> echo valueCopy.toString() echo val.toString() }.curry(value) } closures }

Creo que es su bucle for, pero independientemente, cada vez que no utilice los bucles clásicos de "estilo C", tendrá que marcar su función como NonCPS.