Flux不会在“ then”之前等待元素完成

时间:2020-06-26 09:11:24

标签: java spring-boot netty spring-webflux project-reactor

我无法理解该问题,并且不确定自己在做什么错

我要等待流量结束,然后返回serverResponse的单声道

我已附上代码片段,doOnNext将填充categoryIdToPrintRepository

我一直在研究如何在磁通量结束后返回单声道,并找到了'then',但仍然在处理onNextSite之前执行'then'方法,结果是错误:

java.lang.IllegalArgumentException: 'producer' type is unknown to ReactiveAdapterRegistry

我在做什么错了?

 public Mono<ServerResponse> retrieveCatalog(ServerRequest ignored) {
        return Mono.just("start").flatMap(id ->
                Flux.fromIterable(appSettings.getSites())
                        .subscribeOn(ForkJoinPoolScheduler.create("SiteCatalogScheduler"))
                        .doOnNext(this::onNextSite)
                        .then(Mono.from(ServerResponse.ok().body(categoryIdToPrintRepository.getSortedTreeValues(), String.class))));

    }

    private void onNextSite(Integer siteId) {
        IntStream.range(1, appSettings.getCatalogMaxValue()).parallel().forEach(catalogId -> {
            Optional<SiteCatalogCategoryDTO> cacheData =
                    siteCatalogCacheUseCaseService.getSiteCatalogResponseFromCache(siteId, catalogId);
            cacheData.ifPresentOrElse(siteCatalogCategoryDTO -> {/*do nothing already exist in cache*/},
                    () -> {
                    Mono<SiteCatalogCategoryDTO> catalogCategoryDTOMono = WebClient.create(getUri(siteId, catalogId))
                            .get().retrieve().bodyToMono(SiteCatalogCategoryDTO.class);
                    catalogCategoryDTOMono.subscribe(siteCatalogCategoryDTO ->
                            handleSiteServerResponse(siteCatalogCategoryDTO, siteId, catalogId));
            });
        });
    }


    private void handleSiteServerResponse(SiteCatalogCategoryDTO siteCatalogCategoryDTO,
                                          int siteId, int catalogId) {
        if (siteCatalogCategoryDTO.getResponseStatus().equals(ResponseStatus.SUCCESS))
            Flux.fromIterable(siteCatalogCategoryDTO.getMappingList())
                    .subscribe(mapSCC -> {
                        categoryIdToPrintRepository.insertIntoTree(mapSCC.getCategoryId(),
                                "Site " + siteId + " - Catalog " + catalogId + " is mapped to category " + "\"" +
                                        mapSCC.getCategoryName() + "\" (" + mapSCC.getCategoryId() + ")");
                        siteCatalogCacheUseCaseService.insertIntoSiteCatalogCache(siteId, catalogId, siteCatalogCategoryDTO);
                    });
    }

1 个答案:

答案 0 :(得分:1)

您做错了几件事,您不应该在应用程序中subscribe,并且使用的方法无效,除非在特定的地方,否则不应在反应式编程中使用。

这是一些示例代码:


// Nothing will happen, we are not returning anything, we can't subscribe
private void doSomething() {
    Mono.just("Foo");
}

// complier error
doSomething().subscribe( ... );

您的应用程序是publisher的主叫客户端,是订户,这就是为什么我们将Mono或Flux返回给主叫客户端subscribe

您已通过以下方式解决了该问题:

private void doSomething() {
    Mono.just("Foo").subscribe( ... );
}

doSomething();

现在您正在订阅自己的东西,这不是正确的方法,如前所述,主叫客户端是用户,而不是您。

正确的方法:

private Mono<String> doSomething() {
    return Mono.just("Foo");
}

// This is returned out to the calling client, they subscribe
return doSomething();

当Mono / Flux完成时,它将发出一个信号,该信号将触发链中的下一个,下一个和下一个。

因此,我对您需要做的事情的看法如下:

  • 删除全部 subscribes,如果您想做某事,可以使用flatmapmapdoOnSuccess等功能。链完好无损地传递给客户。
  • 删除所有 void 函数,确保它们返回FluxMono,如果您想返回某些内容,请返回{通过使用Mono<Void>函数来{1}},以便链条完整。

使用Mono / Flux时,您需要处理退货,以便其他人可以继续使用。

更新:

要触发Mono.empty(),您必须返回一些内容,它会在上一个单音/通量完成时返回。

示例:

then