gkatz
gkatz

Reputation: 133

coordinating multiple outgoing requests in a reactive manner

this is more of a best practice question. in my current system (monolith), a single incoming http api request might need to gather similarly structured data from to several backend sources, aggregate it and only then return the data to the client in the reponse of the API.

in the current implementation I simply use a threadpool to send all requests to the backend sources in parallel and a countdown latch of sorts to know all requests returned.

i am trying to figure out the best practice for transforming the described above using reactice stacks like vert.x/quarkus. i want to keep the reactiveness of the service that accepts this api call, calls multiple (similar) backend source via http, aggregates the data.

I can roughly guess I can use things like rest-easy reactive for the incoming request and maybe MP HTTP client for the backend requests (not sure its its reactive) but I am not sure what can replace my thread pool to execute things in parallel and whats the best way to aggregate the data that returns.

I assume that using a http reactive client I can invoke all the backend sources in a loop and because its reactive it will 'feel' like parralel work. and maybe the returned data should be aggragated via the stream API (to join streams of data)? but TBH I am not sure. I know its a long long question but some pointers would be great.

thanks!

Upvotes: 2

Views: 1155

Answers (1)

tsegismont
tsegismont

Reputation: 9138

You can drop the thread pool, you don't need it to invoke your backend services in parallel.

Yes, the MP RestClient is reactive. Let's say you have this service which invokes a backend to get a comic villain:

@RegisterRestClient(configKey = "villain-service")
public interface VillainService {

    @GET
    @Path("/")
    @NonBlocking
    @CircuitBreaker
    Uni<Villain> getVillain();

}

And a similar one for heroes, HeroService. You can inject them in your endpoint class, retrieve a villain and a hero, and then compute the fight:

@Path("/api")
public class Api {

    @RestClient
    VillainService villains;

    @RestClient
    HeroService heroes;

    @Inject
    FightService fights;

    @GET
    public Uni<Fight> fight() {
        Uni<Villain> villain = villains.getVillain();
        Uni<Hero> hero = heroes.getRandomHero();

        return Uni.combine().all().unis(hero, villain).asTuple()
                .chain(tuple -> {
                    Hero h = tuple.getItem1();
                    Villain v = tuple.getItem2();

                    return fights.computeResult(h, v);
                });
    }
}

Upvotes: 5

Related Questions