0

I have been working with some Reactor Core Java, because I want to figure out if this is possible to solve one problem I currently have using this framework.

At present I have a long, executing job that takes about 40-50 minutes to complete. The method looks more or less like this:

  public void doLongTask(List<Something> list){
    //instructions.
    for(Something sm : list){
      if(condition){
         executeLongOperation();
      }
      //instructions
      if(condition){
       executeLongOperation();
      }
    }
  }

in my controller I have something like this:

@GetMapping(path = "/integersReactor", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Flux<Integer> getIntegersReactor(){
    logger.debug("Request getIntegersReactor initialized.");
    return simpleSearchService.getIntegersReactor();
}

and in the service layer I have something like this:

@Override
public Flux<Integer> getIntegersReactor(){
    return Flux.range(0, Integer.MAX_VALUE);
}

this is just a placeholder that I am using as a proof of concept. My real intentions are to somehow return a Flux of some object that I will define myself, this object will have a few fields that I will use to tell the consumer the status of the job.

Now, things get somewhat complicated now because I would like to send updates as the executeLongOperation(); are executed, and somehow instead of returning a flux of Integers, return a flux of an object that uses the return of executeLongOperation();

Can this be acomplished with Flux? How can I leverage Reactor Core java to push the return values of all of the times executeLongOperation(); is executed into a reactive stream that can be passed to the controller the same way that getIntegersReactor() does it in my example?

1 Answers1

0

Yes it should be possible, but since the executeLongOperation is blocking, it will need to be offset on a dedicated thread (which reduces the benefits you get from a top-to-bottom reactive implementation).

Change your doLongTask to return a Flux<Foo>, make it concatenate Monos that wrap executeLongOperation on a dedicated thread (or better yet, change the executeLongOperation itself to return a Mono<Foo> and do the wrapping internally and subscribeOn another thread internally). Something like:

public Flux<Foo> doLongTask(List<Something> list) {
    return Flux.fromIterable(list)
               //ensure `Something` are published on a dedicated thread on which
               //we can block
               .publishOn(Schedulers.elastic()) //maybe a dedicated Scheduler?
               //for each `Something`, perform the work
               .flatMap(sm -> {
                 //in case condition is false, we'll avoid long running task
                 Flux<Foo> work = Flux.empty();
                 //start declaring the work depending on conditions
                 if(condition) {
                     Mono<Foo> op = Mono.fromCallable(this::executeLongOperation);
                     work = conditional.concatWith(op);
                 }
                 //all other instructions should preferably be non-blocking
                 //but since we're on a dedicated thread at this point, it should be ok
                 if(condition) {
                     Mono<Foo> op = Mono.fromCallable(this::executeLongOperation);
                     work = conditional.concatWith(op);
                 }
                 //let the flatMap trigger the work
                 return work;
               });
}
Simon Baslé
  • 27,105
  • 5
  • 69
  • 70