简体   繁体   中英

A java application with J2V8 crashes when an exception happened in a some deferred section (e.g. setTimeout or process.nextTick)

I use amazing J2V8 java library which allows execute any Javascript code in your Java application furthermore it can integrates a nodeJS engine.

But i have encountered with a next issue. This code interrupts a Java application immediately after nodejs invokes a callback function of setTimeout which throw an exception although there is a try..carch block. The exception doesn't even enter into the try..catch block.

// It is an example, in real case it can be a some erorr in a code.
nodeJS = NodeJS.createNodeJS();
try {
    nodeJS.getRuntime().executeVoidScript("setTimeout(function(){throw 'Error'}, 1000);"); 
} catch (Exception e) {
    e.printStackTrace();
}

The application is interrupted with message:

undefined:1
setTimeout(function(){throw 'Error'}, 10000);
                  ^
Error
Process finished with exit code 1

Another example shows that exceptions are not a cause of interruption of an application always and it is a 'normal' case.

nodeJS = NodeJS.createNodeJS();
try {
    nodeJS.getRuntime().executeVoidScript("throw 'Error'");
} catch (Exception e) {
    e.printStackTrace();
}

In this case we see the only a error message in console but the application still works.

Exception in thread "Thread-2" undefined:1: Error
throw 'Error'
^
com.eclipsesource.v8.V8ScriptExecutionException
    at com.eclipsesource.v8.V8._executeScript(Native Method)
    at com.eclipsesource.v8.V8.executeScript(V8.java:940)
    at com.eclipsesource.v8.V8.executeScript(V8.java:595)
    at com.eclipsesource.v8.V8.executeObjectScript(V8.java:625)
    at com.eclipsesource.v8.V8.executeObjectScript(V8.java:608)
    at org.efc.origamiapp.v8.V8Environment.run(V8Environment.java:383)

The examples above are in the try..catch blocks, and you can see trace stack below it. So the interruption is fired in Native Method (the secod example), but in the first case the JS exception just kills the Java application without any explanations in a console or in a trace log.

It looks like the error you are throwing in the javascript code is being propagated into the java environment. This is what one would expect to see given the js code you are trying to execute ( throw 'Error' ). What did you expect to happen? Simply catch any exceptions in java and handle appropriately - maybe by logging?

try {
    nodeJS.getRuntime().executeVoidScript("throw 'Error'"); 
}
catch(Exception e) { 
    System.out.println(e.toString()); 
}

This is the best and correct solution.

process.on('unhandledRejection', (err) => {
    console.error('Unhandled promise rejection',err);
});
process.on('uncaughtException', (err) => {
    console.error('Uncaught exception',err);
});

For more information see the nodeJS documentation: Event: 'uncaughtException'

For now my workaround is this script.

let nativeSetTimeout = setTimeout;
setTimeout = function(fn, t){
    let safeFn = () => {
        try {
            fn();
        } catch(e){
            console.log(e);
        }
    };
    return nativeSetTimeout(safeFn,t);
} 


let nativeNextTick = process.nextTick;
process.nextTick = function(){
    let args = Array.prototype.slice.call(arguments);
    let fn = args[0];
    let safeFn = () => {
        try {
            fn.apply(null,args.slice(1));
        } catch(e){
            console.log(e);
        }
    };
    return nativeNextTick(safeFn);
}

I invoke this script in a beginning of an application.

nodeJS.getRuntime().executeVoidScript(workaroundScript);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM