ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("nashorn");
Mono.fromRunnable(() -> {
System.out.println("11111");
try {
System.out.println("2222");
jsEngine.eval("print("hello");while(1);");
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("3333");
}).timeout(Duration.ofMillis(2000)).doOnError(Exception.class, e -> {
System.out.println("4444");
System.out.println(e.toString());
}).onErrorResume(Exception.class, e -> {
System.out.println("5555");
return Mono.error(e);
}).block();
System.out.println("end!!!");
这段代码永远不会结束。 它显示"java.util.concurrent.TimeoutException:在 2000 毫秒内未在"source(MonoRunnable("中观察到任何项目或终端信号(并且未配置回退( ".
我想在 2 秒内终止它,然后看到"结束!!"。
如何解决这个问题?
这是对 reactor 的一个相当奇怪的用法 - 如果你真的想在 2 秒后超时,那么更正常/更好的方法可能是在新线程中生成你的eval()
,并在一段时间后interrupt()
该线程(然后根据需要处理InterruptedException
。
但是,要直接回答这个问题,您在链末端的onErrorResume()
调用本身正在返回一个Mono.error
(本质上是它正在处理的相同错误Mono
的克隆。当您调用block()
时,将引发此异常。
相反,您可能希望返回Mono.empty()
,而不是在该onErrorResume()
块中Mono.error(e)
。
我这样嘟囔着。但我不确定这是一个好方法。 我正在等待更好的主意。
ScriptEngineManager scriptEngineMgr = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineMgr.getEngineByName("nashorn");
String script = "$result.test = 1;nwhile(1);";
Thread th = new Thread(() -> {
jsEngine.put("$result", new JSONObject());
try {
jsEngine.eval(script);
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
Mono.defer(() -> {
th.start();
try {
th.join();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return Mono.just(true);
}).timeout(Duration.ofSeconds(2)).doOnError(TimeoutException.class, e -> {
// e.printStackTrace();
System.out.println(th.isAlive());
th.stop();
}).doAfterTerminate(() -> {
System.out.println(result);
System.out.println("end!!!");
System.out.println(th.isAlive());
}).onErrorReturn(false).block();