I'm trying to implement node fail-over logic. Like the
retry block, but each time on a different node.
So I supply a list of nodes, and use code like the following where the
node parameter is a
Nodes and Labels parameter:
def failover(b, nodes) {
guard {
b(nodes.head())
} rescue {
recurse(b, nodes.tail())
}
}
failover({ n -> build("zzzz_node", NODE:n) }, ["one", "two", "three", "four", "five"])
This works fine. The problem I'm having is that if one of the nodes is offline, it hangs forever. I've tried using the
Build Timeout Plugin on that job, but it doesn't work, presumably because the job itself never starts.
So I'm trying to wrap the build in a concurrent.Future so that I can time it out from the DSL:
f = { build("zzzz_node", NODE:"one") } as Callable
executor = Executors.newSingleThreadExecutor()
future = executor.submit(f)
result = future.get(2, TimeUnit.SECONDS)
executor.shutdownNow()
This gives me a massive stack trace:
ERROR: Failed to run DSL Script
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252)
at java.util.concurrent.FutureTask.get(FutureTask.java:111)
at java_util_concurrent_Future$get.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at Script1.run(Script1.groovy:15)
<snip>
Caused by: java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.GetEffectivePojoPropertySite.acceptGetProperty(GetEffectivePojoPropertySite.java:51)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
at com.cloudbees.plugins.flow.FlowDelegate.statusCheck(FlowDSL.groovy:167)
at com.cloudbees.plugins.flow.FlowDelegate.build(FlowDSL.groovy:173)
at sun.reflect.GeneratedMethodAccessor5604.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
<snip>
Looking at the source code for the
FlowDSL, I see that when they do this sort of thing for the
parallel block, they muck around with ACLs, Contexts, and FlowStates.
Before I start tunneling to the center of the earth, does anyone know how I can get this to work?
Thanks!