在热流上重试操作?

时间:2018-06-29 18:06:25

标签: java project-reactor

Flux.just(1, 2, 3)
        .doOnNext(__ -> System.out.println("producing number: " + __))
        .publish()
        .autoConnect()
        .doOnNext((Integer __) -> {
            System.out.println("throwing error.");
            throw new RuntimeException("aaa");
        })
        .retry(1, error -> true)
        .subscribe(number -> System.out.println("I will never be here..."),
                error -> System.out.println("will I be here? " + error),
                () -> System.out.println("completed!"));

输出:

producing number: 1
throwing error.
producing number: 2
producing number: 3

预期的输出:(根据我的逻辑-我确定我弄错了)

producing number: 1
throwing error.
producing number: 2
throwing error.
producing number: 3

为什么输出不同于预期的输出?

1 个答案:

答案 0 :(得分:2)

这有点棘手,但归结为:

调用publishautoConnect的效果是,一旦您订阅,就会创建一个内部订阅,即使取消外部订阅,该内部订阅也会保留。可以将其视为由publishautoConnect连接的两个流。

--inner stream--> publish/connect-> --outer stream--> subscriber

无论外部流发生什么,内部流将继续运行。这是因为您有一个热门观察站,并且可能有多个订阅者。如果一个断开连接,则其他连接仍然希望从流中获得值。换句话说,发布运算符告诉源代码,它可以根据需要生成值。

    --inner stream--> publish/connect-> --outer stream--> subscriber1
                                        --outer stream--> subscriber2

您可以通过删除retry来验证该行为。数字1和2仍将被打印。如果希望源停止产生值,则可以使用refCount代替autoConnect。如果没有更多订阅者,refCount将取消内部流。

这是棘手的部分:该流是同步的,Streams are just functions。实际情况要复杂一些,但是retry运算符内部的subscription函数将运行,直到内部流完成为止。只有这样,它才能重新订阅。

与异步流不同,例如由Flux.interval创建。

Flux.interval(Duration.ofSeconds(1))
    .doOnNext(__ -> System.out.println("producing number: " + __))
    .publish()
    .autoConnect()
    .doOnNext((Integer __) -> {
        System.out.println("throwing error.");
        throw new RuntimeException("aaa");
    })
    .retry(1)
    .subscribe()

当您呼叫.subscribe()时,retry将在doOnNext上内部呼叫订阅,依此类推,直到Flux上的第一个doOnNext呼叫subscribe为止。间隔Flux说“好吧,我会在一秒钟内发出第一个值”,并且订阅已建立。

一秒钟后,发出一个值,引发错误,重试运算符再次订阅。

在您的示例中,在完全建立订阅之前,Flux已经开始在订阅调用期间发出值,可以这么说。