如何取消正在进行的Spring Flux?

时间:2018-08-10 12:16:54

标签: spring reactive-programming spring-webflux project-reactor

我正在使用弹簧通量向服务发送并行请求,这是它的非常简化的版本:

Flux.fromIterable(customers)
  .flatMap { customer ->
     client.call(customer)
  } ...

我想知道如何取消这种磁通,例如,以某种方式获取对磁通的引用并告诉其关闭。

2 个答案:

答案 0 :(得分:5)

您可能已经知道,对于反应性对象,all operators are lazy。这意味着流水线的执行被延迟到您订阅反应流之前。

因此,在您的示例中,没有任何要取消的操作,因为此时未发生任何事情。

但是假设您的示例扩展到:

Disposable disp = Flux.fromIterable(customers)
  .flatMap { customer ->
     client.call(customer)
  }
  .subscribe();

然后,如您所见,订阅将返回一个Disposable对象,您可以根据需要取消整个操作,例如

disp.dispose()

dispose的文档说:

  

取消或处置基础任务或资源。

another section of the documentation内容如下:

  

[运算符的]这些变体返回对订阅的引用   当没有更多数据时,可用于取消订阅   需要。取消后,来源应停止产生值,并且   清理它创建的所有资源。此取消和清理行为   在Reactor中由通用的Disposable接口表示。

因此取消流的执行在反应性对象方面并非没有复杂性,因为如果要在处理过程中取消流,则要确保使世界保持一致状态。例如,如果您正在构建某些东西,则可能要丢弃资源,破坏任何部分聚合结果,关闭文件,通道,释放内存或拥有的任何其他资源,从而可能撤消更改或对其进行补偿。

您可能需要阅读cleanup上的文档,以便您也可以考虑在反应式对象方面可以做什么。

Flux<String> bridge = Flux.create(sink -> {
    sink.onRequest(n -> channel.poll(n))
        .onCancel(() -> channel.cancel()) 
        .onDispose(() -> channel.close())  
    });

答案 1 :(得分:2)

@Edwin的回答很准确。只要您不调用订阅,就不会取消任何内容,因为不会执行任何代码。
只是想添加一个示例以使其清楚。

public static void main(String[] args) throws InterruptedException {

   List<String> lists = Lists.newArrayList("abc", "def", "ghi");
   Flux<String> end = Flux.fromIterable(lists)
                           .delayElements(Duration.ofSeconds(3))
                           .map(String::toLowerCase)
                           .subscribe(System.out::println);

   Thread.sleep(5000); //Sleeping so that some elements in the flux gets printed
   subscribe.dispose();

   Thread.sleep(10000); // Sleeping so that we can prove even waiting for some time nothing gets printed after cancelling the flux
}

但是我想说一种更简洁的方法(函数方法)是利用takeUntiltake之类的函数。例如,在上述示例中,我也可以像这样停止流。

List<String> lists = Lists.newArrayList("abc", "def", "End", "ghi");
Flux.fromIterable(lists).takeUntil(s -> s.equalsIgnoreCase("End"))
                           .delayElements(Duration.ofSeconds(3))
                           .map(String::toLowerCase)
                           .subscribe(System.out::println);

List<String> lists = Lists.newArrayList("abc", "def", "ghi");
Flux.fromIterable(lists).take(2)
                           .delayElements(Duration.ofSeconds(2))
                           .map(String::toLowerCase)
                           .subscribe(System.out::println);