在我的生产代码中,当Mono超时时,我的日志中出现错误。
我设法用以下代码重新创建了这些错误:
@Test
public void testScheduler() {
Mono<String> callableMethod1 = callableMethod();
callableMethod1.block();
Mono<String> callableMethod2 = callableMethod();
callableMethod2.block();
}
private Mono<String> callableMethod() {
return Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"));
}
在Mono.fromCallable
中,我正在使用第三方库进行阻止呼叫。通话超时后,我收到类似于
reactor.core.publisher.Operators - Operator called default onErrorDropped
reactor.core.publisher.Operators - Scheduler worker in group main failed with an uncaught exception
这些错误似乎也是断断续续的,有时在我运行提供的代码时,我根本没有任何错误。但是,当我在说10的循环中重复通话时,我始终如一地接听电话。
答案 0 :(得分:3)
问题:为什么会发生此错误?
答案:
给 timeout()运算符指定的持续时间过去后,将引发 TimeoutException 。结果如下:
onError 信号被发送到主反应链。结果,恢复了主要执行,进程继续进行(即,执行了 onErrorResume())。
在结果#1之后不久, fromCallable()中定义的异步任务被中断,从而触发第二个异常( InterruptedException )。主反应式链不再能够处理此 InterruptedException ,因为 TimeoutException 首先发生并且已经导致主反应链恢复(注意:不会产生第二个 onError 信号的过程符合无功流规范-> Publisher #7)。
由于主链无法妥善处理第二个异常( InterruptedException ),因此Reactor将其记录为错误级别,以使我们知道发生了意外异常。
问题:如何摆脱它们?
简短答案:使用Hooks.onErrorDropped()更改日志级别:
Logger logger = Logger.getLogger(this.getClass().getName());
@Test
public void test() {
Hooks.onErrorDropped(error -> {
logger.log(Level.WARNING, "Exception happened:", error);
});
Mono.fromCallable(() -> {
Thread.sleep(60);
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
长答案:如果您的用例允许,则可以处理在 fromCallable()中发生的异常,因此影响主链的唯一异常是 TimeoutException 。在这种情况下, onErrorDropped()不会首先出现。
@Test
public void test() {
Mono.fromCallable(() -> {
try {
Thread.sleep(60);
} catch (InterruptedException ex) {
//release resources, rollback actions, etc
logger.log(Level.WARNING, "Something went wrong...", ex);
}
return "Success";
})
.subscribeOn(Schedulers.elastic())
.timeout(Duration.ofMillis(50))
.onErrorResume(throwable -> Mono.just("Timeout"))
.doOnSuccess(result -> logger.info("Result: " + result))
.block();
}
其他参考: