【问题标题】:Managing the lifecycle of multiple Flux with spring-data-mongodb-reactive使用 spring-data-mongodb-reactive 管理多个 Flux 的生命周期
【发布时间】:2020-12-09 18:12:28
【问题描述】:

我有一个数据服务,我正在认真考虑切换到响应式模型。这是一个联合查询引擎,可以通过调用一个或多个“解析器”实现来解析查询数据,具体取决于查询类型。

如果我切换到 spring-data-mongodb-reactive,那么这些实现中的每一个都必须为以下各项创建多个 Flux 实例:

  1. 对信息不同部分的查询
  2. 从 #1 查询每个查询的所有数据库

注意:我不想合并每个Flux,因为能够将上述#1 的查询分开,使最终处理更容易。将所有联合数据库的每个“部分”查询组合起来就可以了,但我必须将每个“部分”的数据分开。我希望这是有道理的。

解释完整的工作流程超出了本文的范围,但我想知道如何创建任意数量的 Flux 实例,并订阅它们以启动它们,然后等到它们全部完成后再继续处理跨所有联合源的完全检索数据。在 Java 中,我正在寻找类似于 CompletableFuture.allOf() 的东西。

如果我做这样的事情,我是否已经接近正确的轨道了:

public class ReactiveDataService {
    private static final Supplier<Example<String>> example1 = () -> Example.of("Example 1");
    private static final Supplier<Example<String>> example2 = () -> Example.of("Example 2");
    private static final Supplier<Example<String>> example3 = () -> Example.of("Example 3");
    private static final Supplier<Example<String>> example4 = () -> Example.of("Example 4");
    private static final Supplier<Example<String>> example5 = () -> Example.of("Example 5");
    private final Collection<ReactiveMongoRepository<String, String>> repositories;

    public ReactiveDataService(Collection<ReactiveMongoRepository<String, String>> repositories) {
        this.repositories = repositories;
    }

    private void processFluxes(final Flux<String> flux1, final Flux<String> flux2, final Flux<String> flux3,
                               final Flux<String> flux4, final Flux<String> flux5) {
        // Call service to process flux stuff
    }

    /**
     * For all repositories, combine fluxes that run the same query.
     * Subscribe to each flux immediately to get the query started.
     * Add all fluxes to a container flux that processes the results
     * upon completion.
     * After everything is set up, block until completion.
     */
    public void doQuery() {
        final Flux<String> flux1 = Flux.fromIterable(repositories)
                .flatMap(repo -> repo.findAll(example1.get()));
        flux1.subscribe();

        final Flux<String> flux2 = Flux.fromIterable(repositories)
                .flatMap(repo -> repo.findAll(example2.get()));
        flux2.subscribe();

        final Flux<String> flux3 = Flux.fromIterable(repositories)
                .flatMap(repo -> repo.findAll(example3.get()));
        flux3.subscribe();

        final Flux<String> flux4 = Flux.fromIterable(repositories)
                .flatMap(repo -> repo.findAll(example4.get()));
        flux4.subscribe();

        final Flux<String> flux5 = Flux.fromIterable(repositories)
                .flatMap(repo -> repo.findAll(example5.get()));
        flux5.subscribe();

        final Flux<Flux<String>> fluxes = Flux.just(flux1, flux2, flux3, flux4, flux5)
                .doOnComplete(() -> processFluxes(flux1, flux2, flux3, flux4, flux5));
        fluxes.blockLast();
    }
}

【问题讨论】:

    标签: mongodb reactive-programming spring-data-mongodb project-reactor spring-data-mongodb-reactive


    【解决方案1】:

    这是一个如何使用 Mono.zip 的示例:

        public static void main(String[] args) {
            Flux<String> flux0 = Flux.empty();
            Flux<String> flux1 = Flux.just("1.1", "1.2", "1.3");
            Flux<String> flux2 = Flux.just("2.1", "2.2", "2.3");
            Flux<String> flux3 = Flux.just("3.1", "3.2", "3.3");
            
            Mono.zip(lists -> process(lists), flux0.collectList(), flux1.collectList(), flux2.collectList(), flux3.collectList()).block();
        }
        
        private static String process(Object[] lists) {
            System.out.println("List 0 is " + lists[0]);
            System.out.println("List 1 is " + lists[1]);
            System.out.println("List 2 is " + lists[2]);
            System.out.println("List 3 is " + lists[3]);
            return "output";
        }
    

    哪个输出:

    List 0 is []
    List 1 is [1.1, 1.2, 1.3]
    List 2 is [2.1, 2.2, 2.3]
    List 3 is [3.1, 3.2, 3.3]
    

    所以你可以根据你的情况调整它。

    请注意,Mono.zip 不能返回 null,这就是为什么我将“输出”作为结果,但如果您不需要任何输出,您可以输入任何您想要的不为 null 的内容。

    思路是先将每一个Flux&lt;String&gt;转换成Mono&lt;List&lt;String&gt;&gt;,使用collectList,这样处理起来会更简单。 Mono.zip 允许您等待所有操作完成,并将输出处理为Object[]。您可以将每个对象转换为List&lt;String&gt; 进行处理。

    【讨论】:

    • 这接近我需要的,但我需要能够区分列表。如果我的列表都包含相同类型的对象,那么 Object[] 可以工作,但我会有不同的参数化类型。
    • 我不太清楚。在 Object[] 中,每个 Object 对应于单个 Flux 的结果,其顺序与您在方法 zip() 中给出的顺序相同,这就是为什么它只是 Object,因为每个 Flux 可能有不同的类型。因此,您可以按顺序区分它们,并将 Object 转换为相应的类型。在示例中,输出显示每个 Object 实际上本身就是一个 List(在我的示例中为 String)。或者可能是我不太明白你的意思
    • 好吧,也许我误解了你。我现在对你正在做的事情有了更好的了解。但看起来它们是在每个输入产生 a 值之后组合在一起的。一切都完成后,我需要能够处理一切。
    • zip 方法的JavaDoc:Aggregate given monos into a new Mono that will be fulfilled when all of the given Monos have produced an item, aggregating their values according to the provided combinator function. 因此,一旦所有项目都产生了,就会调用 process 方法。因为我在每个 Flux 上都使用了collectList,所以一旦 Flux 完成,它将生成一个 List。所以最后,当所有都完成时调用 process 方法。
    • 嗨,锌。我刚刚在阅读您提到的javadoc,我看到从Flux 到Mono 的转换意味着通量已完成,而“项目的发射”是Flux 的完成结果。所以感谢您的帮助和耐心!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多