弹簧+助焊剂的奇怪行为。我有Python服务器代码(使用Flask,但这并不重要,请将其视为伪代码)是流式响应:
def generate():
for row in range(0,10):
time.sleep(1)
yield json.dumps({"count": row}) + '\n'
return Response(generate(), mimetype='application/json')
这样,我模拟了处理列表中的某些任务,并在结果准备好后立即将结果发送给我,而不是等待所有操作完成,主要是避免将所有内容先保存在服务器的内存中,然后再保存到服务器的内存中。客户。现在,我想通过Spring WebClient来使用它:
Flux<Count> alerts = webClient
.post()
.uri("/testStream")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToFlux( Count.class )
.log();
alerts.subscribe(a -> log.debug("Received count: " + a.count));
Mono<Void> mono = Mono.when(alerts);
mono.block();
log.debug("All done in method");
这是我要登录的日志:
2019-07-03 18:45:08.330 DEBUG 16256 --- [ctor-http-nio-4] c.k.c.restapi.rest.Controller : Received count: 8
2019-07-03 18:45:09.323 INFO 16256 --- [ctor-http-nio-2] reactor.Flux.MonoFlatMapMany.4 : onNext(com.ksftech.chainfacts.restapi.rest.Controller$Count@55d09f83)
2019-07-03 18:45:09.324 INFO 16256 --- [ctor-http-nio-2] reactor.Flux.MonoFlatMapMany.4 : onComplete()
2019-07-03 18:45:09.325 DEBUG 16256 --- [io-28088-exec-4] c.k.c.restapi.rest.Controller : All done in method
2019-07-03 18:45:09.331 INFO 16256 --- [ctor-http-nio-4] reactor.Flux.MonoFlatMapMany.4 : onNext(com.ksftech.chainfacts.restapi.rest.Controller$Count@da447dd)
2019-07-03 18:45:09.332 DEBUG 16256 --- [ctor-http-nio-4] c.k.c.restapi.rest.Controller : Received count: 9
2019-07-03 18:45:09.333 INFO 16256 --- [ctor-http-nio-4] reactor.Flux.MonoFlatMapMany.4 : onComplete()
请注意mono.block返回后,subscribe如何处理最后一个对象。我知道Reactor是异步的,一旦它看不到更多对象,它就会释放Mono并并行订阅我的代码。然后,调度程序会先看到先运行什么。
我想出了一个很丑陋的想法,即订阅了completeConsumer并使用了良好的旧等待/通知。然后工作正常。但是,有没有更优雅的方法来确保我的方法一直等到Flux的所有元素都处理完了?
答案 0 :(得分:0)
好的,我已经研究了这一领域,并意识到Reactor用于异步执行。如果需要同步,则必须使用同步。为了使代码在所有订阅都完成之后执行,我需要使用doOnComplete:
public class FluxResult {
public boolean success = true;
public Exception ex = null;
public void error() {success = false;}
public void error(Exception e) {success = false; ex = e;}
public synchronized void waitForFluxCompletion() throws InterruptedException {
wait();
}
public synchronized void notifyAboutFluxCompletion() {
notify();
}
}
.... // do something which returns Flux
myflux
.doFirst(() -> {
// initialization
})
.doOnError(e -> {
log.error("Exception", e);
})
.doOnComplete(() -> {
try {
// finalization. If we were accumulating objects, now flush them
}
catch (Exception e) {
log.error("Exception", e);
flux_res.error(e);
}
finally {
flux_res.notifyAboutFluxCompletion();
}
})
.subscribe(str -> {
// something which must be executed for each item
});
然后等待对象发出信号:
flux_res.waitForFluxCompletion();
if (!flux_res.success) {
if (flux_res.ex != null) {