问题
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