【问题标题】:Inconsistent handling of Mono.error(OutOfMemoryError)pMono.error(OutOfMemoryError)p 处理不一致
【发布时间】:2021-11-10 17:44:48
【问题描述】:

我试图了解如果您订阅带有几个变体的 Mono.error(new OutOfMemoryError("hello world")) 会发生什么。

我通过了这些测试(使用 reactor-core 3.4.3):

    @Test
    public void oom() {
        Mono.error(new OutOfMemoryError("hello world")).subscribe();
    }

    @Test
    public void oom_thenReturn() {
        try {
            Mono.error(new OutOfMemoryError("hello world")).thenReturn(123).subscribe();
            fail("Expected OOMError");
        } catch (OutOfMemoryError e) {
            // expected
        }
    }

    @Test
    public void oom_then_thenReturn() {
        Mono.error(new OutOfMemoryError("hello world")).then().thenReturn(123).subscribe();
    }

    @Test
    public void genericError_thenReturn() {
        Mono.error(new Error("hello world")).thenReturn(123).subscribe();
    }

因此,如果您订阅Mono.error(new OutOfMemoryError("hello world")).thenReturn(123),它会在订阅线程上引发异常。但是如果你省略了thenReturn(123) 调用,在它之前添加一个额外的then() 调用,或者使用通用的Error 而不是OutOfMemoryError,订阅线程上不会抛出异常。 (如果您添加日志记录 Subscriber,您会看到 onSubscribeonError 被按预期调用。)

我知道为什么OutOfMemoryError 会与Error 受到不同的处理,但我不明白为什么thenReturn(123) 调用会导致错误传播到订阅线程,而并非如此。谁能解释一下?

【问题讨论】:

  • 我对reactor不太熟悉,但是由于异步性,您的测试是否会在抛出异常之前完成?也许你应该打电话给block()而不是subscribe()
  • 确实所有block() 调用都会在这种情况下抛出。但是,上述行为是 100% 可重现的(至少对我而言),所以它看起来不像是竞争条件。
  • 另外,如果我使用StepVerifier,那么我会看到相同的模式:StepVerifier.create(Mono.error(new OutOfMemoryError("hello world"))).expectError().verify() 通过,但使用StepVerifier.create(Mono.error(new OutOfMemoryError("hello world")).thenReturn(123)).expectError().verify()verify() 调用会抛出OutOfMemoryError。 (据我了解,StepVerifier 旨在消除竞争条件。)

标签: java project-reactor


【解决方案1】:

OutOfMemoryError 在 Reactor 中被视为不可恢复的异常。它可能会抛出它而不是把它变成一个合适的onError 信号。

项目反应堆reference:

然而,Reactor 定义了一组异常(例如 OutOfMemoryError) 总是被认为是致命的。见 Exceptions.throwIfFatal 方法。这些错误意味着 Reactor 无法 继续运行并被抛出而不是传播。

【讨论】:

  • 但是为什么Mono.error(new OutOfMemoryError("hello world"))Mono.error(new OutOfMemoryError("hello world")).thenReturn(123) 的行为不同呢?
  • @PeteGillin 我猜Mono.error(new OutOfMemoryError("hello world")).thenReturn(123) 失败了,因为它继续运行。我已经更新了我的答案,包括相应的参考资料。
  • 啊,我想这是有道理的,我认为我们正在取得进展。谢谢!
  • 但是您能解释一下为什么Mono.error(new OutOfMemoryError("hello world")).then().thenReturn(123) 的行为类似于Mono.error(new OutOfMemoryError("hello world")) 而不是Mono.error(new OutOfMemoryError("hello world")).thenReturn(123)then() 调用会传播错误,所以我不明白为什么这不能算作“继续运行”。
  • @PeteGillin 这对我来说似乎很正常,因为then() 正是我们需要的:传播错误信号。重要的是要知道OutOfMemoryError 是一个致命错误,可能会导致不可预知的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
  • 2020-07-12
  • 1970-01-01
  • 2012-08-30
  • 2019-12-31
  • 2020-07-09
相关资源
最近更新 更多