简体   繁体   中英

How do I create a Flux where each element of the flux is a polling operation and terminate the flux on success or error?

Similar to How to process each product one by one with incremental progress update using Spring reactive?

The thing I want to do is given

enum Status {
  PROCESSING,
  ERROR,
  COMPLETE
}
record MyResp {
  String requestId;
  Status status;
  double progress;
  URI result;
  String errorMessage;
};

Mono<MyResp> requestSomethingSlow(MyReqObjectNotRelevant request);
/**
 * Sets status to SUCCESS or return a Mono.error()
 */
Mono<MyResp> checkIfDone(String requestId);

I want a method like:

Flux<MyResp> requestSomethingSlowFlux(MyReqObjectNotRelevant request, Duration delay) {

   return ...???
     ??? requestSomethingSlow(request)
     . ???
     .delayElements(delay)
     . ???
     . checkIfDone(...?)
     ...???

}

I am thinking it's something like Flux.generate but how do I convert the Mono<MyResp> to a Callable and use it with the generator function?

I was also looking at Mono.expand as shown in How do I create a Flux using generate wrapping calls that return a Mono but that wouldn't work because I don't have a finite set of calls.

So far my implementation attempt looks like

Flux<MyResp> requestSomethingSlowFlux(MyReqObjectNotRelevant request, Duration delay) {

   return requestSomethingSlow(request)
     .flatMapMany(initialResponse -> {
       if (initialResponse.getStatus() == COMPLETE) {
         return Flux.just(initialResponse);
       } else if (initialResponse.getStatus() == ERROR) {
         return Flux.error(
           new IllegalStateException(
             initialResponse.getErrorMessage()));
       } else {
         ... still figuring this part out
       }
     }
     .delayElements(delay)
     
}

Also similar to How do you implement Polling Logic in Project Reactor? but I want it as a flux of events that show progress rather than all or none.

Using this answer but removing the last() call so I get all events.

Flux<MyResp> requestSomethingSlowFlux(MyReqObjectNotRelevant request, Duration delay) {

   return requestSomethingSlow(request)
     .flatMapMany(initialResponse -> {
       if (initialResponse.getStatus() == COMPLETE) {
         return Flux.just(initialResponse);
       } else if (initialResponse.getStatus() == ERROR) {
         return Flux.error(
           new IllegalStateException(
             initialResponse.getErrorMessage()));
       } else {
         return checkIfDone(initialResponse.getRequestId())
           .repeatWhen(repeat -> repeat.delayElements(delay))
           .doNext(response -> {
             if (response.getStatus() == ERROR) {
               throw new IllegalStateException(
                 initialResponse.getErrorMessage());
             }
           })
           .takeUntil(response -> response.getStatus() != PROCESSING)
       }
     });
     
}

It has a few flaws though

  1. the status processing is more or less repeated from the initial response
  2. the delay is part of the Mono and not part of the Flux. Therefore, I cannot make it return the flux and have the delayElements on the flux. I think it's the choice of repeatWhen

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM