2

I intend to write a process() method with project-reactor library

The process() method takes a byte array as a parameter and goes through the following steps. Assume all other methods for each step is written and ready to be used.

  1. deserialize the byte array to a Message object
  2. extract userID, userStatus and userAddress from the Message object
  3. retrieve a record by userId from the database
  4. update the record with userStatus and userAddress if these two value extracted from Message objects are not Null.
  5. save the record in the database
@Component
public class UserService {

    @Autowired
    private Repository repo;

    //this is the method I want to fix
    public Mono<User> process(byte[] byteArray) {
        Message msg = deserialize(byteArray).block();  --> Question #1
        String userId = extractUserId(msg);
        String userStatus = extractUserStatus(msg);
        String userAddress = extractUserAddress(msg);
        return repo.find(userId)
                .switchIfEmpty(Mono.defer(() -> {
                    log.error("Error Message");
                    return Mono.empty();
                }))
                .map(user -> {
                    if(userStatus != null) {
                        user.setStatus(userStatus);
                    }

                    if(userAddress != null) {
                        user.setAddress(userAddress);
                    }
                })
                .flatmap(repo::save);
    }

    private Mono<Message> deserialize(byte[] byteArray) {
        //assume this method is written and is ready to be invoked;
    }

    private String extractUserId(Message msg) {
        //assume this method is written and is ready to be invoked;
    }

    private String extractUserStatus(Message msg) {
        //assume this method is written and is ready to be invoked;
    }

    private String extractUserAddress(Message msg) {
        //assume this method is written and is ready to be invoked;
    }

}

public class Repository {
    public Mono<User> find (String id) {
        //assume this method is written and is ready to be invoked;
    }

    public Mono<User> save(User user) {
        //assume this method is written and is ready to be invoked;
    }
}

Question 1: I am not supposed to block it, but I have to extractId from it for retrieving a record from the database and also use it later on for extracting userStatus and address.

Question 2: Should extractUserId, extractUserStatus and extractUserAddress methods return Mono?

ChiGuy001
  • 31
  • 4

1 Answers1

0

Question 1: I am not supposed to block it, but...

It's not so much as you're not supposed to, but you can't block it (unless you employ tactics such as spinning up thread pools for particular parts of the chain where you have no other option, which is messy and often signals you're not ready to move to a fully reactive stack anyway.) In a fully reactive chain, any blocks are going to kill the chain dead, tying up your precious event loop thread(s) and crippling performance.

Instead, you'd keep it as a Mono<Message> and then do what you need to with that - so with your current implementation it might look something like this:

return deserialize(byteArray)
    .flatMap(
        msg -> {
          String userId = extractUserId(msg);
          String userStatus = extractUserStatus(msg);
          String userAddress = extractUserAddress(msg);

          return repo.find(userId)
              .switchIfEmpty(
                  Mono.defer(
                      () -> {
                        log.error("Error Message");
                        return Mono.empty();
                      }))
              .map(
                  user -> {
                    if (userStatus != null) {
                      user.setStatus(userStatus);
                    }

                    if (userAddress != null) {
                      user.setAddress(userAddress);
                    }
                  })
              .flatmap(repo::save);
        });

Should extractUserId, extractUserStatus and extractUserAddress methods return Mono?

This depends on what those methods need to do. Would they have to block if they didn't return mono? If yes, then they should return Mono (instead of blocking.) If they don't need to block, then there's no reason for them to return mono (and indeed they shouldn't, as that could lead a developer to make false assumptions about those methods.)

Note that this is the case for your deserialize() method as well. If it's taking a byte array, then it may not need to perform any blocking operation (the usual reason that deserialisation would be blocking is because it's reading from an inputstream or similar, not because of the actual deserialisation itself.)

Michael Berry
  • 70,193
  • 21
  • 157
  • 216