如何在不关闭流的情况下从流量收集

时间:2018-06-22 15:30:45

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

我的用例是创建一个像这样的反应性端点:

public Flux<ServerEvent> getEventFlux(Long forId){
    ServicePoller poller = new ServicePollerImpl();
    Map<String,Object> params =  new HashMap<>();
    params.put("id", forId);

    Flux<Long> interval = Flux.interval(Duration.ofMillis(pollDuration));
    Flux<ServerEvent> serverEventFlux =
            Flux.fromStream(
                    poller.getEventStream(url, params) //poll a given endpoint after a fixed duration.
            );
    Flux<ServerEvent> sourceFlux= Flux.zip(interval, serverEventFlux)
             .map(Tuple2::getT2); // Zip the two streams. 
/* Here I want to store data from sourceFlux into a collection whenever some data arrives without disturbing the downstream processing in Spring. So that I can access collection later on without polling again */

这会在数据可用时立即将其发送回前端,但是我的第二个用例是在数据到达一个单独的集合时将其合并,以便如果以后有类似的请求到达,我可以卸载来自池的整个数据而无需再次点击服务。

我试图在从原始流量控制器返回之前,先预订磁通量,缓冲区,缓存并收集流量,但所有这些似乎都关闭了流,因此Spring无法对其进行处理。

在不关闭助焊剂流的情况下,什么时候可以使用助焊剂并将值存储到集合中?

遇到异常:

  

java.lang.IllegalStateException:流已被操作   或在关闭   java.util.stream.AbstractPipeline.spliterator(AbstractPipeline.java:343)   〜[na:1.8.0_171]在   java.util.stream.ReferencePipeline.iterator(ReferencePipeline.java:139)   〜[na:1.8.0_171]在   Reactor.core.publisher.FluxStream.subscribe(FluxStream.java:57)   〜[reactor-core-3.1.7.RELEASE.jar:3.1.7.RELEASE]在   Reactor.core.publisher.Flux.subscribe(Flux.java:6873)   〜[reactor-core-3.1.7.RELEASE.jar:3.1.7.RELEASE]在   Reactor.core.publisher.FluxZip $ ZipCoordinator.subscribe(FluxZip.java:573)   〜[reactor-core-3.1.7.RELEASE.jar:3.1.7.RELEASE]在   Reactor.core.publisher.FluxZip.handleBoth(FluxZip.java:326)   〜[reactor-core-3.1.7.RELEASE.jar:3.1.7.RELEASE]

2 个答案:

答案 0 :(得分:1)

poller.getEventStream返回一个Java 8流,该流只能使用一次。您可以先将流转换为集合,也可以使用供应商来推迟执行poller.getEventStream

Flux.fromStream(
  () -> poller.getEventStream(url, params)
);

答案 1 :(得分:0)

一个更好的Oliver建议的对我有用的解决方案

public Flux<ServerEvent> getEventFlux(Long forId){
        ServicePoller poller = new ServicePollerImpl();
        Map<String,Object> params =  new HashMap<>();
        params.put("id", forId);

        Flux<Long> interval = Flux.interval(Duration.ofMillis(pollDuration));
        Flux<ServerEvent> serverEventFlux =
                Flux.fromStream(
                        ()->{
                        return poller.getEventStream(url, params).peek((se)->{reactSink.addtoSink(forId, se);});
                        }
                );
        Flux<ServerEvent> sourceFlux= Flux.zip(interval, serverEventFlux)
                 .map(Tuple2::getT2);

        return sourceFlux;

    }