响应式里出错之后流还能继续吗?onErrorResume 写在哪里差别多大?retry 为什么会重复发元素?timeout 限的是什么?为什么日志里会冒出 onErrorDropped?这篇用 Reactor 3.8.7 逐个验证。
不处理:[1, 2, ERROR(IllegalStateException: bad-3)] 用时 10 ms
onErrorReturn(-1):[1, 2, -1, COMPLETE] 用时 0 ms
onErrorResume(e -> Flux.just(100, 200)):[1, 2, 100, 200, COMPLETE] 用时 1 ms
onErrorMap(包成 RuntimeException("wrapped", e)):[1, 2, ERROR(RuntimeException: wrapped:bad-3)] 用时 12 ms
onErrorComplete():[1, 2, COMPLETE] 用时 0 ms
onErrorContinue((e, v) -> 跳过出错的元素)+ map:[1, 2, 4, 5, COMPLETE] 用时 1 ms
onErrorContinue 对 flatMap 里返回 Mono.error 的元素:[10, 20, 40, 50, COMPLETE] 用时 2 ms
同样的 flatMap,不用 onErrorContinue:[10, 20, ERROR(IllegalStateException: bad-3)] 用时 0 ms错误终止流;onErrorReturn / Resume 继续发;恢复写在内层只替换单个元素。
内层 onErrorResume(放在 flatMap 里面):[10, 20, -3, 40, 50, COMPLETE] 用时 0 ms 外层 onErrorResume(放在 flatMap 后面):[10, 20, -1, COMPLETE] 用时 0 ms 内层 onErrorResume 里再抛异常:[10, 20, ERROR(IllegalArgumentException: handler-failed)] 用时 1 ms
内层隔离单个元素的失败,外层整个流结束。
retry(5):[ok-on-attempt-3, COMPLETE] 用时 0 ms;上游被订阅 3 次,副作用执行 3 次 retry(2) 一直失败:[ERROR(IllegalStateException: always-fail-3)] 用时 0 ms;上游被订阅 3 次 Retry.max(2) 一直失败:[ERROR(RetryExhaustedException: Retries exhausted: 2/2)] 用时 7 ms;上游被订阅 3 次 Retry.backoff(3, 100ms) 一直失败:[ERROR(RetryExhaustedException: Retries exhausted: 3/3)] 用时 809 ms;上游被订阅 4 次 Retry.backoff(3, 100ms).jitter(0) 一直失败:[ERROR(RetryExhaustedException: Retries exhausted: 3/3)] 用时 720 ms;上游被订阅 4 次 Retry.fixedDelay(3, 100ms).filter(e -> false):[ERROR(IllegalStateException: always-fail-1)] 用时 1 ms;上游被订阅 1 次 Retry.backoff(3, 100ms).jitter(0).onRetryExhaustedThrow(原异常):[ERROR(IllegalStateException: always-fail-4)] 用时 725 ms;上游被订阅 4 次 Flux 在第 3 个元素处失败,retry(5):[1, 2, 1, 2, 1, 2, 3, COMPLETE] 用时 0 ms;上游被订阅 3 次(前面的元素重复发出)
重新订阅整条上游,Flux 会重复发元素,backoff 耗尽抛 RetryExhaustedException。
Mono.delay(300ms).timeout(100ms):[ERROR(TimeoutException: Did not observe any item or terminal signal within 100ms in 'source(MonoDelay)' (and no fallback has been configured))] 用时 105 ms
Mono.delay(300ms).timeout(100ms, Mono.just(-1L)):[-1, COMPLETE] 用时 113 ms
Flux.interval(100ms).take(5).timeout(300ms)(总共 500ms,每个间隔 100ms):[0, 1, 2, 3, 4, COMPLETE] 用时 513 ms
Flux.concat(interval(100ms).take(3), Mono.delay(500ms)).timeout(300ms)(第 4 个迟到):[0, 1, 2, ERROR(TimeoutException: Did not observe any item or terminal signal within 300ms in 'source(FluxConcatArray)' (and no fallback has been configured))] 用时 614 ms
超时会取消上游:[ERROR(TimeoutException: Did not observe any item or terminal signal within 100ms in 'peek' (and no fallback has been configured))]
cancelled(上游收到取消信号)= true,阻塞里的 Thread.sleep 被中断 = true,任务正常跑完 = false
timeout(100ms) 放在 retry 之前(每次尝试各自限时):[fast-3, COMPLETE] 用时 211 ms;上游被订阅 3 次
timeout(100ms) 放在 retry 之后(整体限时):[ERROR(TimeoutException: Did not observe any item or terminal signal within 100ms in 'retry' (and no fallback has been configured))] 用时 111 ms;上游被订阅 1 次Flux 上限制元素间隔;超时取消上游;与 retry 的顺序决定是每次限时还是整体限时。
timeout(100ms) 取消订阅之后,源头(Mono.create 的 sink)才报错:[ERROR(TimeoutException: Did not observe any item or terminal signal within 100ms in 'source(MonoCreate)' (and no fallback has been configured))]
被 Hooks.onErrorDropped 收到的错误 = []
Flux.merge(两个都会报错的源):[ERROR(IllegalStateException: A)]
被 Hooks.onErrorDropped 收到的错误 = [](第二个错误去了哪里,这里没有看到)
违反协议的源:onComplete 之后又 onError:[COMPLETE]
被 Hooks.onErrorDropped 收到的错误 = [IllegalStateException: after-complete]
没有自定义 hook 时的默认行为是在标准错误输出打一行 [ERROR] Operator called default onErrorDropped(见最后几行)
-- 标准错误里出现的 "Operator called default onErrorDropped" 日志共 2 行:
[ERROR] (boundedElastic-1) Operator called default onErrorDropped - java.lang.InterruptedException: sleep interrupted
[ERROR] (main) Operator called default onErrorDropped - java.lang.IllegalStateException: after-complete取消之后的错误大多消失;违反协议的源才进 onErrorDropped。