Catching an exception when loading a groovy file

荒凉一梦 提交于 2020-03-23 04:06:52

问题


I have these 3 groovy files:

A.groovy:

// ...
stage("Test")
{
    throw new Exception("This script fails")
}

B.groovy:

// ...
stage("Test")
{
    // Nothing, want this to pass
}

main.groovy:

// ...
m = [:]
status = [:]
scripts = ["A", "B"]
for script in scripts
{
    m["${script}"] = 
    {
        stage("${script}")
        {
            try
            {
                 load "${script}.groovy"
                 status["${script}"] = true
            }
            catch (Exception e)
            {
                 status["${script}"] = false   
            }
        }
    }
}

parallel m

for result_iterator in status:
    print "${result_iterator.key} resulted in ${result_iterator.value}"

The code above is a sketch of the real code =) When I run main.groovy to see the results in the status dictionary, I only get to see B. A threw an exception and thus it didn't add itself to the dictionary. Is there a way I can catch A's exception somehow?


回答1:


Problem 1

You got bitten by the way Groovy closures capture variables outside of their scope. The references to script inside the closure will receive the value of script at the time when the closure is run, which will be the last value of script. So both closures actually load "B.groovy" and the exception is never thrown!

The fix is simple, just create a local variable inside of the loop that captures the current value of script:

for( script in scripts ) {
    def theScript = script
    // Now only use theScript inside of the closure!
}

Problem 2

You are not serializing write access to the status variable from parallel threads. This could result in very nasty, hard-to-reproduce bugs.

The fix is to use Map.asSynchronized() to create a synchronized map:

status = [:].asSynchronized()

Complete 'main.groovy' fix

m = [:]
status = [:].asSynchronized()  // because multiple threads write to this variable
scripts = ["A", "B"]

for( script in scripts ) {
    def theScript = script  // Important to pass the current value into the closure!

    m[ theScript ] = {
        stage( theScript ) {
            try {
                 load "${theScript}.groovy"
                 status[ theScript ] = true
            }
            catch (Exception e) {
                 status[ theScript ] = false   
            }
        }
    }
}

parallel m

for( result_iterator in status ) {
    print "${result_iterator.key} resulted in ${result_iterator.value}"
}

Note: I have also removed the unnecessary string interpolations.



来源:https://stackoverflow.com/questions/60680669/catching-an-exception-when-loading-a-groovy-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!