Vano
Vano

Reputation: 1538

collect data from Jenkins pipeline parallel steps

What would be the best way to collect data (such as pass/fail results) from parallel steps.

What I've reached so far:

#!groovy
def fspam(name, spam){
    spam[name] = "BEEN THERE TOO"
}

// pipeline
node('slave'){
    stage("test"){
        targets = ["a", "b"]
        def tasks = [:] 
        def spam = [:]
        targets.each{ tasks["${it}"] = {
            node('slave'){
                echo "dry-run ${it}"
                spam[it] = "BEEN THERE" <--- works
                fspam(it)         <--- fails
            } 
        } 

        }
        parallel tasks
        print("spam")
        print(spam)
    }
}

But it failed with:

Also: groovy.lang.MissingPropertyException: No such property: stam for class: WorkflowScript groovy.lang.MissingPropertyException: No such property: stam for class: WorkflowScript at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)

  1. Seems that in-closure it populates the map successfully, but when using function it throws error
  2. I don't sure having a global map is the best/cleanest way

Any suggestions

Upvotes: 2

Views: 1918

Answers (2)

S. Shuck
S. Shuck

Reputation: 56

Use .asSynchronized():

targets = ["a", "b"]

tasks = [:]
spam = [:].asSynchronized()

targets.each { target ->
    tasks[target] = {
        echo "dry-run ${target}"
        spam[target] = "BEEN THERE"
        fspam(target, spam)         // <--- passing spam fixes the issue
    } 
}

parallel tasks

print("spam")
print(spam)

This guarantees that updates to the map are thread-safe. For collecting a list, you can use [].asSynchronized(). Link

Upvotes: 4

Vano
Vano

Reputation: 1538

Well, missed an obvious solution:

#!groovy
def fspam(name, spam){
    spam[name] = "BEEN THERE TOO"
}

// pipeline
node('slave'){
    stage("test"){
        targets = ["a", "b"]
        def tasks = [:] 
        def spam = [:]
        targets.each{ tasks["${it}"] = {
            node('slave'){
                echo "dry-run ${it}"
                spam[it] = "BEEN THERE"
                fspam(it, spam)         <--- passing spam fixes the issue
            } 
        } 

        }
        parallel tasks
        print("spam")
        print(spam)
    }
}

one question remains: is there better/cleaner way?(thread safety/jenkins pipeline native, etc)

Upvotes: 1

Related Questions