如何立即从Mono.zip返回服务器已发送事件?

时间:2019-07-29 14:39:14

标签: java spring spring-webflux reactor

在以下示例中,我希望端点直接发出Server Sent Events,或至少在1-2秒后发出。

但是实际上,首先汇总所有1000页,然后发出事件。

@GetMapping(value = "/test", produces = TEXT_EVENT_STREAM_VALUE)
public Flux<JSONObject> test(Integer pages) {
    int pages = 1000; //for showcase
    return Flux.range(0, pages)
            .map(pageNumber -> Arrays.asList(1 * pageNumber, 2 * pageNumber, 3 * pageNumber))
            .flatMap(numbers -> Mono.zip(a(numbers), b(numbers)))
            .map(tuple -> {
                JSONObject json = new JSONObject();
                json.put("test", tuple);
                return json;
            });
}

问题:每个页面完成后,我需要更改什么以获得即时事件?

有趣的是,如果我删除.flatMap(zip...)行并在最后的.map()方法内添加一个sleep命令,则我将每100ms直接接收一个事件:

 Flux.range(0, pages)
        .map(pageNumber -> Arrays.asList(1 * pageNumber, 2 * pageNumber, 3 * pageNumber))
        .map(tuple -> {
            TimeUnit.MILLISECONDS.sleep(100); //direct events each 100ms
            JSONObject json = new JSONObject();
            json.put("test", tuple);
            return json;
        });

所以这是我想要的结果,但是现在如何向其中添加一个并行运行多个子方法的非阻塞zip并汇总结果(我认为这是zip的目的)?

旁注:我知道这个例子本身没有任何意义,只是为了说明我的问题,即在每页之后都无法直接获取SSE。

对于此问题的目标,压缩方法无关紧要,但是要完整:

    private Mono<String> a() {
        return Mono.fromCallable(() -> {
            TimeUnit.MILLISECONDS.sleep(100); //simulate slow service
            return "a";
        });
    }

    private Mono<String> b() {
        return Mono.fromCallable(() -> "b");
    }

2 个答案:

答案 0 :(得分:1)

我怀疑您需要链接Mono.zip才能使其正常工作。

@GetMapping(value = "/test", produces = TEXT_EVENT_STREAM_VALUE)
public Flux<JSONObject> test(Integer pages) {
    int pages = 1000;
    return Flux.range(0, pages)
        .map(pageNumber -> Arrays.asList(1 * pageNumber, 2 * pageNumber, 3 * pageNumber))
        .flatMap(numbers -> {
            return Mono.zip(a(numbers), b(numbers))).map(tuple -> {
               JSONObject json = new JSONObject();
               json.put("test", tuple);
               return json; 
            });
}

答案 1 :(得分:0)

我必须添加一个.range().subscribeOn(Schedulers.elastic()),至少在使用它时可以使用。虽然我不知道为什么。