user871611
user871611

Reputation: 3462

Mono: Return results from a long running method

Currently I'm beginnging with Spring + reactive programming. My aim is to return a result in a REST-endpoint from a long running method (polling on a database). I'm stuck on the api. I simply don't know how to return the result as Mono in my FooService.findFoo method.

@RestController
public class FooController {

  @Autowired
  private FooService fooService;

  @GetMapping("/foo/{id}")
  private Mono<ResponseEntity<Foo> findById(@PathVariable String id) {
    return fooService.findFoo(id).map(foo -> ResponseEntity.ok(foo)) //
      .defaultIfEmpty(ResponseEntity.notFound().build())
  }
  ...
}

@Service
public class FooService {

  public Mono<Foo> findFoo(String id) {
    // this is the part where I'm stuck
    // I want to return the results of the pollOnDatabase-method
  }

  private Foo pollOnDatabase(String id) {
    // polling on database for a while
  }
}

Upvotes: 0

Views: 895

Answers (2)

Szil&#225;rd Fodor
Szil&#225;rd Fodor

Reputation: 364

Use the Mono.fromSupplier method! :)

@Service
public class FooService {

  public Mono<Foo> findFoo(String id) {
    return Mono
      .fromSupplier(() -> pollOnDatabase(id))
      .subscribeOn(Schedulers.boundedElastic());
  }

  private Foo pollOnDatabase(String id) {
    // polling on database for a while
  }
}

With this method we return a Mono value ASAP, constant time with a supplier which will be evaluated on demand by the caller's subscribe. This is the non blocking way to call a long-running-blocking method.

BE AWARE that without subscription on boundedElastic the blocking pollOnDatabase method will block the original thread, which leads to thread starvation. You can find different schedules for every kind of tasks here.

DO NOT use Mono.just with long-running calculations as it will run the calculation before returning the Mono instance, thereby blocking the given thread.

+1: Watch this video to learn to avoid "reactor meltdown". Use some lib to detect blocking calls from non-blocking threads.

Upvotes: 1

pvpkiran
pvpkiran

Reputation: 27068

It's pretty simple. You could just do

@Service
public class FooService {

  public Mono<Foo> findFoo(String id) {
    return Mono.just(pollOnDatabase(id));
  }

  private Foo pollOnDatabase(String id) {
    // polling on database for a while
  }
}

Upvotes: 0

Related Questions