web-dev-qa-db-ja.com

進行中のSpringFluxをキャンセルするにはどうすればよいですか?

スプリングフラックスを使用して並列リクエストをサービスに送信しています。これは非常に単純化されたバージョンです。

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

どうすればこのフラックスをキャンセルできるのだろうと思っていました。たとえば、フラックスへの参照を何らかの方法で取得して、シャットダウンするように指示します。

6
kms333

ご存知かもしれませんが、リアクティブオブジェクトの場合、 すべての演算子は怠惰です 。これは、パイプラインの実行が、リアクティブストリームにサブスクライブする瞬間まで遅延されることを意味します。

したがって、あなたの例では、その時点では何も起こっていないため、キャンセルするものはまだありません。

しかし、あなたの例が次のように拡張されたと仮定します。

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

次に、ご覧のとおり、サブスクリプションはDisposableオブジェクトを返します。このオブジェクトを使用して、必要に応じてすべてをキャンセルできます。

disp.dispose()

dispose のドキュメントによると:

基になるタスクまたはリソースをキャンセルまたは破棄します。

ドキュメントの別のセクション 次のように書かれています:

[演算子の]これらのバリアントは、データが不要になったときにサブスクリプションをキャンセルするために使用できるサブスクリプションへの参照を返します。キャンセルすると、ソースは値の生成を停止し、作成したリソースをクリーンアップする必要があります。このキャンセルとクリーンアップの動作は、Reactorでは汎用のDisposableインターフェースによって表されます。

したがって、ストリームの実行をキャンセルしても、リアクティブオブジェクト側での問題が発生することはありません。処理の途中でストリームをキャンセルする場合は、ワールドを一貫した状態のままにしておく必要があるためです。たとえば、何かを構築している場合は、リソースを破棄したり、部分的な集計結果を破棄したり、ファイルやチャネルを閉じたり、メモリやその他のリソースを解放したりして、変更を元に戻したり、それらを補正したりできます。

これについては cleanup のドキュメントを読み、リアクティブオブジェクト側で何ができるかについても検討することをお勧めします。

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

@Edwinからの回答は正確です。 subscribeを呼び出さない限り、コードは実行されないため、キャンセルすることはできません。
わかりやすくするために例を追加したかっただけです。

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

   List<String> lists = Lists.newArrayList("abc", "def", "ghi");
   Disposable disposable = 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
   disposable.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);
1
pvpkiran