Search code examples
javaspring-bootreactive-programmingspring-webfluxreactor

Returning results while a task is still running


I have a method that needs to return results immediately after it's called, even all the tasks in this method are not complete.

In this scenario:

  1. User submits an address to deposit funds to
  2. I want to save their addresses and send them a deposit address
  3. I want to start a task to start checking if the user deposited their funds to the deposit address

Step 2 is what I am returning and step 3 is what I want to keep running in the background after I return to step 3.

I am not sure what direction to take to orchestrate these events. Below is my method, not sure exactly what to do about the addressRegistrationService.watchAndTransact(userAddresses); task. It could take up to a full day to complete and the user needs the deposit address returned before it can deposit the funds.

@PostMapping("/registeraddress")
public ResponseEntity<Mono<UserAddressesDTO>> addUserAddress(@RequestBody UserAddresses userAddresses) throws Exception {
    log.info("Registering {} with addresses {}", userAddresses.getAccountId(), userAddresses.getAddresses());

    //Checking if we can use the user provided addresses and account id
    if (addressRegistrationService.isRegistrationValid(userAddresses)) {
        throw new InvalidAddressException("Address is invalid");
    }

    log.info("Deposit Address is {}", generateJobcoinAddress.generateJobcoinAddress());

    //Generate the deposit address and add it the UserAddress
    String depositAddress = generateJobcoinAddress.generateJobcoinAddress();

    //Add input and deposit address to the object
    UserAddressesDTO userAddressesDTO = new UserAddressesDTO(userAddresses.getAccountId(), depositAddress, userAddresses.getAddresses());

    //Request the Jobcoin Service to start watching for the transaction
    //Once Jobcoin Service detects it will post the transaction to the house account
    //then to the user addresses - > we will be notified separately once this is complete
    addressRegistrationService.watchAndTransact(userAddresses);

    //Store addresses in database, calls the data-service to store these details
    return ResponseEntity.ok().body(addressRegistrationService.saveAddressDB(userAddressesDTO));
}

Solution

  • You can use CompletableFuture. So your code will look like...

    CompletableFuture.runAsync(() -> addressRegistrationService.watchAndTransact(userAddresses));
    

    It will run your watchAndTransact method in a different thread. And main thread will not wait for result. So basically it will run on background.

    Note: But incase of failure you will not know whats happened. So you can add some custom metrics & logs. This can be part of service it-self.

    CompletableFuture.runAsync(() -> {
        try {
            addressRegistrationService.watchAndTransact(userAddresses);
            // Notify user
        } catch (RuntimeException e) {
            // custom metrics implementation here
            // log error here
        }
    });