9

Мы выполняем динамическое создание параллельных шагов на некоторых наших работах. Благодаря this thread я нашел, как динамически создавать карту с параметрами для использования на параллельном шаге.Currying groovy Закрытие CPS для параллельного выполнения

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

Однако карри кажется неправильным. Ссылка на переменную цикла (valueCopy) внутри закрытия делает правильную вещь (as mentioned here), но currying не делает то, что я ожидаю.

Я делаю что-то неправильно, это просто не поддерживается (пока), есть ли какие-нибудь обходные пути? Возможно, это ошибка в трубопроводе Дженкинса?

Надеюсь, что кто-нибудь подскажет, почему это не работает и/или как заставить его работать.

Jenkins: LTS (2.32.1) & последние обновления плагинов от 2017/01/19.

Pipeline скрипт выполняется:

Защиту echoSome (значение) { эхо вал }

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() 

Выход:

[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 

Ожидаемый результат:

[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 

ответ

0

Найдено, что с последней Pipeline: Groovy плагин (2.40) в сочетании с по меньшей мере Дженкинс версии 2.60.3 (работает, хотя плагины стартовой состояния, что вам нужно, по крайней мере Дженкинс 2.73.3) все работает ожидается.

4

Я не уверен, если это выделка, или цикл, но эта функция должна быть помечена как NonCPS, как описано здесь: https://github.com/jenkinsci/pipeline-examples/blob/master/docs/BEST_PRACTICES.md#groovy-gotchas

По существу, это сделать:

@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 
} 

Я думаю, что это ваш цикл for, но независимо от того, в любое время, когда вы не используете классические петли «C Style», вам нужно отметить свою функцию как NonCPS.

+0

Спасибо за ответ. По какой-то причине меня не уведомили :(Я постараюсь попробовать как можно скорее. –

+0

Отмечено так, как это было решено, поскольку это действительно решает мой вопрос. К сожалению, я пропустил упоминание об этом, конечно, я хотел бы использовать код CPS внутри параллельные замыкания :( –

0

Это, по-видимому, является ограничением языка Groovy или Jenkins groovy, я не уверен, что, но стоит отметить, что их примеры выполняются точно так же, как вы это сделали, объявив новую переменную для каждой итерации петля.

Они прокомментировали их пример

// свежую переменную каждой итерации; i будет мутированным

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

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