Search code examples
spring-webfluxproject-reactorreactivespring-data-cassandra

To use Spring data Cassandra Reactive or not


I have the following scenario :

For a given request, we call a function with 2 different sets of parameters. The results from these functions are aggregated and sent as a Map. Function that is called returns a CompletableFuture. Function issues maximum of 4 Async (Listenable Future) cassandra queries. The result from the queries are processed in the order in which they are issued. Based on some conditions the function could return after processing the response from the first query or process all the responses to get the desired result.

Function

@Async
public Map<String,Price> getPricing(String assetType,String code) {
//Issue Query 1 - Returns ListenableFuture
//Issue Query 2 
//Issue Query 3
//Issue Query 4

Query 1 result satisfies return , else continue to Query 2 , followed by 3 and 4.
}

Service

public Map<String,Price> getPrice(String assetType) {

CompletableFuture<Map<String,Price>> a = .getPrice(assetType,"A");
CompletableFuture<Map<String,Price>> b = .getPrice(assetType,"B");

//Join A and B and return the result
}

Is this a better candidate for Spring Webflux + Reactive Spring data cassandra ? What would be the implementation approach ?


Solution

  • To be honest it is kind of hard to answer without some more details. Mostly what kind of condition the result of the query has to satisfy in order to stop evaluating and return result. The conditional logic is hard when dealing with streams. What you can do is for example:

    public Mono<Map<String, Person>> findCustomersAndGroupByName(){
        List<String> customer_id = ImmutableList.of("customer id 1", "customer id 2");
    
        return customerRepo
                .findAllById(customer_id)
                .filter(customer -> customer.getLastname().equals("Smith"))
                .switchIfEmpty(archivedCustomersRepo.findAllById(customer_id)) //if non of the customers has last name smith this will be evaluated
                .filter(customer -> customer.getLastname().equals("Smith"))
                .switchIfEmpty(associatedCustomersRepo.findAllById(customer_id)) //if non of the customers has last name smith this will be evaluated
                .filter(customer -> customer.getLastname().equals("Smith"))
                .collectMap(person -> person.getFirstname()) //grup by first name and return
        ;
    

    }

    this are all reactive repositories. so they look:

    public interface ArchivedCustomersRepo extends ReactiveCassandraRepository<Person, String> {}
    

    But you have to take in to account that in order to take advantage of reactive approach things have to be reactive (non blocking) all the way. That means also your service (I assume you have rest service response at the end of all of this) has to return mono, flux.

    Is is worth it? That depends om the businesses case that you are dealing with. Generally if you have big existing application the answer is no. As there is a big cost in order to shift your mindset (and your colleagues) to more Functional Programming style required by the heavy use of lambda expressions. It took me 2 years.

    Let me know if you have any questions.