Hi Michael,

I had work pipeline job. But after add more environments (envList) job broke with log:

[Pipeline] End of Pipeline
an exception which occurred:
    in field delegate
    in field closures
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@1845f26
Caused: java.io.NotSerializableException: java.util.LinkedHashMap$Entry
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)     at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)     at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)     at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)     at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
    at java.util.LinkedHashMap.internalWriteEntries(LinkedHashMap.java:333)
    at java.util.HashMap.writeObject(HashMap.java:1362)
    at sun.reflect.GeneratedMethodAccessor61.invoke(Unknown Source)


I use NonCPS function sortSuites() and it always return list. I don't have more ideas how to fix. Can you help?

Thank you!

My test pipeline:

#!groovy

def envList = []
envList.add('NODE=behat3 ORO_PHP=7.1 ORO_APP=application/commerce-crm-ee ORO_TEST_SUITE=behat ORO_DB=pgsql BEHAT_MODE=standalone') envList.add('NODE=docker-doc ORO_TEST_SUITE=documentation ORO_APP=documentation/crm ORO_DOC=OroCRM_Documentation') envList.add('NODE=docker-doc ORO_TEST_SUITE=documentation ORO_APP=documentation/commerce ORO_DOC=OroCommerce_Documentation')

envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_APP=application/crm-enterprise      ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=crm-enterprise_1.12  ORO_SE=ES ES_VER=2.4.3 UPGRADE=true TEST_RUNNER_OPTIONS=--group=search,dist') envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_APP=application/crm-enterprise      ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=crm-enterprise_2.0.0 ORO_SE=ES ES_VER=2.4.3') envList.add('NODE=func_2cpu ORO_PHP=7.0 ORO_APP=application/crm-enterprise      ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=crm-enterprise_1.12 UPGRADE=true')

envList.add('NODE=func ORO_PHP=7.1 ORO_APP=application/commerce-enterprise ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=commerce_1.3.0       ORO_SE=ES ES_VER=2.3.5') envList.add('NODE=func ORO_PHP=7.0 ORO_APP=application/commerce-enterprise ORO_TEST_SUITE=functional ORO_DB=MYSQL ORO_INSTALLED=commerce_1.0.0')

envList.add('NODE=func ORO_PHP=7.1 ORO_APP=application/commerce            ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=commerce_1.0.0') envList.add('NODE=func ORO_PHP=7.1 ORO_APP=application/commerce-crm        ORO_TEST_SUITE=functional ORO_DB=PG ORO_ENABLE_PRICE_SHARDING=true')

envList.add('NODE=func ORO_PHP=7.1 ORO_APP=application/commerce-crm-ee     ORO_TEST_SUITE=functional ORO_DB=PG ORO_INSTALLED=commerce_1.3.0') envList.add('NODE=func ORO_PHP=7.1 ORO_APP=application/commerce-crm-ee     ORO_TEST_SUITE=functional ORO_DB=MYSQL ORO_INSTALLED=crm-enterprise_1.12 UPGRADE=true')

envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_APP=application/platform            ORO_TEST_SUITE=functional ORO_DB=PG') envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_APP=application/crm                 ORO_TEST_SUITE=functional ORO_DB=MYSQL')

envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_TEST_SUITE=behat_wiring')
envList.add('NODE=func ORO_PHP=7.1 ORO_TEST_SUITE=javascript JS=YES CS=YES')

envList.add('NODE=func_2cpu ORO_PHP=7.0 ORO_APP=application/commerce-crm-ee     ORO_TEST_SUITE=unit') envList.add('NODE=func_2cpu ORO_PHP=7.1 ORO_APP=application/commerce-crm-ee     ORO_TEST_SUITE=unit')

def behatList = []

def enviroments = [:]
for (int i = 0; i < envList.size() ; i++) {
  int index=i, e = i+1
  enviroments["TestEnv_${e}"] = {
    stage ("TestEnv_${e}"){
        withEnv(["NETWORK=${index}"] + ["TESTENV=TestEnv_${e}"] + envList[index].tokenize()) {
          if (env.ORO_TEST_SUITE == 'behat') {
            node() {
                ws("${HOME}/workspace/dev_${EXECUTOR_NUMBER}") {
                sh """
                   echo "Install"
                """
                behatStr = sh (
                    script: 'echo AutoSuiteSet_1 AutoSuiteSet_2 AutoSuiteSet_3',
                    returnStdout: true
                ).trim()
                }
            }

            behatList=behatStr.tokenize()
            echo "SUITES=${behatList}"
            behatList=sortSuites(behatList)
            echo "SUITES SORTED=${behatList}"
            echo "behatList TYPE=${behatList.getClass()}"
            def enviroments_b = [:]
            for (int j = 0; j < behatList.size() ; j++) {
                int index_b=j
                enviroments_b["TestEnv_${e} behat=${behatList[index_b]}"] = {
                    withEnv(["BEHAT_SUIT=${behatList[index_b]}"]) {
                        node() {
ws("${HOME}/workspace/dev_${EXECUTOR_NUMBER}") {
                                sh """
                                   echo "Run BEHAT_SUIT=$BEHAT_SUIT"
                                """
                            } //workspace
                        } //node
                    } //withEnv
                } //enviroments_b
            } //for
            try {
                parallel enviroments_b
            } catch (error) {
                throw (error)
            }

          } else if (env.ORO_TEST_SUITE == 'functional' || env.ORO_TEST_SUITE == 'unit' || env.ORO_TEST_SUITE == 'behat_wiring' || env.ORO_TEST_SUITE == 'javascript'){
            node() {
                ws("${HOME}/workspace/dev_${EXECUTOR_NUMBER}") {
                sh """
                   echo "Run $ORO_TEST_SUITE"
                """
                }
            }
          } else {
            node() {
                ws("${HOME}/workspace/dev_${EXECUTOR_NUMBER}") {
                sh """
                   echo "Run $ORO_TEST_SUITE"
                """
                }
            }
          }
        }
    }
  }
}
try {
  parallel enviroments
} catch (error) {
  throw (error)
}


@NonCPS
def sortSuites(suites){
    def suitesStat=[AutoSuiteSet_1:435, AutoSuiteSet_2:323, AutoSuiteSet_3:363]
    def suites_time = suitesStat
    // def suites_time = [:]
    def suitesMap = [:]
    if (suites_time.size()>0){
        def timeLimit = suites_time.values().max() //find max value
        for(s in suites){
          x = suites_time.find{ artifact -> artifact.key == s}
          if(x){
            suitesMap.put(x.key, x.value)
          }else{
            suitesMap.put(s, timeLimit)
          }
        }
    }else{
        def suitesList = suites.collect { t -> [t] }
        return suitesList
    }
    tasks = divideList(suitesMap)
    tasks = sortListInMap(tasks)
    tasksList = tasks.collect { t -> t.keySet()}
    return tasksList
}

@NonCPS
def divideList(inputMap){
    // Sort an incoming array in descending order
    inputMap=sortMap(inputMap)
    maxValue = inputMap.values().max()
    // Resulting set of maps
    def outputSet = []
    // Variable for storing an individual map
    def outputMap = [:]
    for (inputElement in inputMap) {
       // We add to the temporary map and consider the resulting sum of the maps items
       possibleMap = outputMap + [inputElement]
       possibleMapSum = possibleMap.values().sum()
        // If the amount in the temporary map is less than maxValue, go to the next iteration, we will try to supplement the map with one more element
       if (possibleMapSum < maxValue) {
           outputMap = possibleMap
        // If the amount in the temporary map is maxValue, add a temporary map to the result set and zero the temporary map
       }else if(possibleMapSum == maxValue) {
           outputSet.add(possibleMap)
           outputMap = [:]
        // If the amount in the temporary map exceeded maxValue, add the previous version of the temporary map to the result set (without the current element), and create a new temporary map with the current element
       }else if(possibleMapSum > maxValue) {
           outputSet.add(outputMap)
           outputMap = [:]
           outputMap.put(inputElement.key, inputElement.value)
       }
    }
    if (outputMap) {
       outputSet.add(outputMap)
    }
    return outputSet
}

@NonCPS
def sortMap(map) {
  map.sort{a, b -> b.value <=> a.value }
}

@NonCPS
def sortListInMap(map) {
    map.sort { a, b -> b.values().sum() <=> a.values().sum() }
}


06.08.2017 17:47, Michael Pailloncy пишет:
It seems like there are some variables used out of their scope and some misused Groovy methods.

Here is a working version, IIUC your pipeline :-)

#!groovy

def behatList =['AutoSuiteSet_0', 'AutoSuiteSet_1', 'AutoSuiteSet_2', 'AutoSuiteSet_3', 'AutoSuiteSet_4', 'AutoSuiteSet_5'] def suitesStat=[AutoSuiteSet_0:0, AutoSuiteSet_1:1, AutoSuiteSet_2:2, AutoSuiteSet_3:3, AutoSuiteSet_4:4, AutoSuiteSet_5:5]

stage("test") {
node('master') {
    behatList2=sortSuites(behatList, suitesStat)
    echo "SUITES2=${behatList2}"
}
}

@NonCPS
def sortSuites(suites, suites_time){
def timeLimit = suites_time.values().max()
def suitesMap= [:]
for(s in suites){
    def x = suites_time.find{ artifact -> artifact.key == s}
if(x){
        suitesMap.put(x.key, x.value)
    }else{
        suitesMap.put(s, timeLimit)
    }
}
def tasks = [suitesMap]
timeLimit = suitesMap.values().max()
while(canSplit(tasks, timeLimit)) {
    tasks = tasks.collect { t ->
if(checkLimit(t, timeLimit)){
            t = splitTo2(t)
        }
        t
    }.flatten()
}
tasks.sort { a, b -> b.values().sum() <=> a.values().sum() }
// tasks = tasks.collect { t -> t.keySet()} // not working, multiple elements are collected here
tasks = tasks.collectMany { t -> t.keySet()}
return tasks
}


@NonCPS
def checkLimit(t, timeLimit) {
if(t.values().sum()>timeLimit && t.size()>1){
return true
}else{
return false
}
}

@NonCPS
def canSplit(tasks, timeLimit) {
for(t in tasks) {
if(checkLimit(t, timeLimit)){
return true
  }
  }
return false
}


@NonCPS
def splitTo2(int_map) {
A=[:]
B=[:]

// int_map.sort{it.value} not working
// for(n in int_map.sort{it.value}) {
for(n in int_map) {
if (A.size() < B.size()) {
        A.put(n.key, n.value)
    }else{
        B.put(n.key, n.value)
    }
}
return [A, B]
}


However, what do you want to achieve exactly ? One of the main advantage of Pipeline is its resumability after restart. But if you use too many @NonCPS, you avoid this feature and this could lead to unexpected behaviour sometimes.

Hopefully it helps :-)


2017-08-04 19:17 GMT+02:00 Slava Dubrovskiy <dub...@gmail.com <mailto:dub...@gmail.com>>:

    Hi.

    I use a special algorithm to pre-sort the steps for parallel start.
    Here is my test pipeline:

    |
    #!groovy

    defbehatList
    
=['AutoSuiteSet_0','AutoSuiteSet_1','AutoSuiteSet_2','AutoSuiteSet_3','AutoSuiteSet_4','AutoSuiteSet_5']
    
defsuitesStat=[AutoSuiteSet_0:0,AutoSuiteSet_1:1,AutoSuiteSet_2:2,AutoSuiteSet_3:3,AutoSuiteSet_4:4,AutoSuiteSet_5:5]

    stage("test"){
        node('master'){
            behatList2=sortSuites(behatList,suitesStat)
            echo "SUITES2=${behatList2}"
    }
    }

    @NonCPS
    defsortSuites(suites,suites_time){
        timeLimit =suites_time.values().max()
    defsuitesMap=[:]
    for(s insuites){
            x=suites_time.find{artifact ->artifact.key ==s}
    if(x){
                suitesMap.put(x.key,x.value)
    }else{
                suitesMap.put(s,timeLimit)
    }
    }
        tasks =[suitesMap]
        timeLimit =suitesMap.values().max()
    while(canSplit()){
            tasks =tasks.collect {t ->
    if(checkLimit(t)){
                    t =splitTo2(t)
    }
                t
    }.flatten()
    }
        tasks.sort {a,b ->b.values().sum()<=>a.values().sum()}
        tasks =tasks.collect {t ->t.keySet()}
    returntasks
    }


    @NonCPS
    defcheckLimit(t){
    if(t.values().sum()>timeLimit &&t.size()>1){
    returntrue
    }else{
    returnfalse
    }
    }

    @NonCPS
    defcanSplit(){
    for(t intasks){
    if(checkLimit(t)){
    returntrue
    }
    }
    returnfalse
    }


    @NonCPS
    defsplitTo2(int_map){
        A=[:]
        B=[:]
    for(n inint_map.sort{it.value}){
    if(A.size()<B.size()){
                A.put(n.key,n.value)
    }else{
                B.put(n.key,n.value)
    }
    }
    return[A,B]
    }

    |


    If I run it, I get the error:
    |
    an exception which occurred:
    infield delegate
    infield closures
    inobjectorg.jenkinsci.plugins.workflow.cps.CpsThreadGroup@7fd2cde1
    Caused:java.io.NotSerializableException:java.util.LinkedHashMap$Entry
     at
    
org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
     at
    
org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
     at
    
org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
     at
    
org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOu
    ...
    |

    Please, help me what is wrong?
    All methods under @NonCPS directive.

    --
    WBR,
    Slava.
-- You received this message because you are subscribed to the Google
    Groups "Jenkins Users" group.
    To unsubscribe from this group and stop receiving emails from it,
    send an email to jenkinsci-users+unsubscr...@googlegroups.com
    <mailto:jenkinsci-users+unsubscr...@googlegroups.com>.
    To view this discussion on the web visit
    
https://groups.google.com/d/msgid/jenkinsci-users/e7a79c56-512f-4706-ab65-9a347966abb3%40googlegroups.com
    
<https://groups.google.com/d/msgid/jenkinsci-users/e7a79c56-512f-4706-ab65-9a347966abb3%40googlegroups.com?utm_medium=email&utm_source=footer>.
    For more options, visit https://groups.google.com/d/optout
    <https://groups.google.com/d/optout>.


--
You received this message because you are subscribed to the Google Groups "Jenkins Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-users+unsubscr...@googlegroups.com <mailto:jenkinsci-users+unsubscr...@googlegroups.com>. To view this discussion on the web visit https://groups.google.com/d/msgid/jenkinsci-users/CAPO77c0_uu7GwQGL3GNGoyh-D878mrbiMj-1fUZefgN0bRPmsA%40mail.gmail.com <https://groups.google.com/d/msgid/jenkinsci-users/CAPO77c0_uu7GwQGL3GNGoyh-D878mrbiMj-1fUZefgN0bRPmsA%40mail.gmail.com?utm_medium=email&utm_source=footer>.
For more options, visit https://groups.google.com/d/optout.

--
WBD,
Viacheslav Dubrovskyi

--
You received this message because you are subscribed to the Google Groups "Jenkins 
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jenkinsci-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jenkinsci-users/2493fd53-6fd8-e528-462f-663457813e98%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to