Search code examples
javajenkinsgroovyjenkins-groovy

How to combine two similar methods into one?


I have two similar methods that differs in their check conditions. Give two similar methods, how can i combine these two into one? Is this possible with closures?

def someCondition = false

def method1() {
    while(!someCondition) {
        def connectionStatus = getConnectionStatus() // return 200, 404, etc.
        if (connectionStatus == 200) {
            someCondition = true
        } else {
            println "repeat until connection is 200"
            sleep 15
        }
    }
}

and

def someCondition = false

def method2(){
    while(!someCondition) {
        def result = getResult() // A, B, C, etc. 
        if (result in ["A", "B", "C"]) {
            someCondition = true
        } else {
            println "waiting until result is either A, B, or C"
            sleep 15
            result = getResult() // call again to check if result changed
        }
    }
}

I could try making it into one method and have different cases where it waits on different if condition depending on the case, but that is no different than just using two different methods. Is there any elegant way to solve this problem in Groovy?


Solution

  • You could write a method like this, which takes a Closure that returns true if successful:

    def waitUntil(int sleep = 1, int maxRetries = 10, Closure<Boolean> test) {
        int retries = 0
        while (retries++ < maxRetries && !test()) {
            println "Failed at attempt $retries/$maxRetries, sleeping for $sleep ms before retrying"
            Thread.sleep(sleep)
        }
    }
    

    Then, you could call it like so:

    waitUntil {
        getResult() in ["A", "B", "C"]
    }
    

    Or make it sleep longer with:

    waitUntil(100) {
        getResult() in ["A", "B", "C"]
    }
    

    Or make it sleep longer between retries, and only retry 5 times:

    waitUntil(100, 5) {
        getResult() in ["A", "B", "C"]
    }
    

    Is that what you meant?

    Edit

    As pointed out, this creates a list each time the closure is called, so for long-running fast looping tasks this could (maybe) create a lot of dead objects for the Garbage Collector to pick up.

    A way to fix this, is to pass the expected values in to the main method, and pass this as an argument to the closure.

    We then only get one list created:

    def waitUntil(expectedResult, int sleep = 1, int maxRetries = 10, Closure<Boolean> test) {
        int retries = 0
        while (retries++ < maxRetries && !test(expectedResult)) {
            println "Failed at attempt $retries/$maxRetries, sleeping for $sleep ms before retrying"
            Thread.sleep(sleep)
        }
    }
    
    waitUntil(["A", "B", "C"]) {
        getResult() in it
    }