1
votes

I'm using GPars' fork/join. When I throw an exception after calling forkOffChild, it gets buried.

For example:

def myRecursiveClosure = { boolean top ->
    try {
        if (!top) {
            throw new RuntimeException('child had a problem')
        } else {
            forkOffChild(false)
        }
    } catch (Exception exc) {
        println 'Exception handled internally'
        throw exc
    }
}

try {
     GParsPool.withPool {
         GParsPool.runForkJoin(true, myRecursiveClosure)
    }
} catch (Exception exc) {
     println 'Exception handled externally'
     throw exc
}

Here, I set a flag so I know the closure has been called recursively. Then, I throw an exception, which gets caught 'internally', but the re-throw is never caught 'externally'. So I am not aware that the forked child failed.

I tried the exception handler also, but it doesn't seem to get called either.

Is this expected behavior, or am I doing something wrong? Are there any strategies to help with this? I can't have the child silently fail.

Thanks!

1

1 Answers

3
votes

The important piece here is that forkOffChild() doesn't wait for the child to run. It merely schedules it for execution. So you cannot expect the forkOffChild() method to propagate exceptions from the child, since they are likely to happen long after the parent has returned from the forkOffChild() method.

Typically, however, a parent is interested in the outcome of the child computations, so it at some point after forking off collects the results using the getChildrenResults() method. This gives you back a list of calculated values or re-throws potential exceptions.

This snippet shows a minimal change to get the expected behavior:

   try {
        if (!top) {
            throw new RuntimeException('child had a problem')
        } else {
            forkOffChild(false)
            println childrenResults
        }
    } catch (Exception exc) {
        println 'Exception handled internally'
        throw exc
    }