QueryGatway Scatter-gather query

Hello Axon framework team.

I want use query gateway scatterGather method. How I understood this method working in the principle send request more than two query handlers and scatterGather method their response merged to a one response.
Below my code how I use this Scatter-gather method.

1. Code

Stream<GtETicketResponseBuyTicket1>  buyTicketDirection = queryGateway.scatterGather("reservationPlacesStartQuery",
        event,
        ResponseTypes.instanceOf(GtETicketResponseBuyTicket1 .class),
        10,
        TimeUnit.SECONDS);

buyTicketDirection.collect(Collectors.toList());

Query handlers

2.Code

@QueryHandler(queryName = "reservationPlacesStartQuery")
public GtETicketResponseBuyTicket1 reservationPlacesStartQuery1(ReservationStartEvent reservationStartEvent) {
    return new GtETicketResponseBuyTicket1();
}

3.Code

@QueryHandler(queryName = "reservationPlacesStartQuery")
public GtETicketResponseBuyTicket1 reservationPlacesStartQuery2(ReservationStartEvent reservationStartEvent) {
    return new GtETicketResponseBuyTicket1();
}

My problem in the when I call 1.Code working good and come to 2.Code query handler and return result but do not come to 3.Code. Where I done mistake or not realized QueryGateway scatterGather working principle?

Hi Dilshod,

Firstly, I’d like to point out this is not a place to talk directly to the Axon Framework/Server team, it’s a place to talk to all the users of Axon products.
You can thus direct your questions to the entirety of the community instead of just towards the Axon Team. :slight_smile:

Secondly, the answer to your situation depends on where code snippets 2 and 3 are in your code base.
Are both present in the same class? If the answer is yes, than that’s the issue.
When dispatching a query, the QueryBus will select the first query handler in a given Query Handling Component.
Thus if both are present in the same class, aka the same Query Handling Component, only one of them will be called to handle the given query.

Lastly, I’d like to point out that you’re mixing message types in your example.
You’re dispatching a query, using an event message, the ReservationStartEvent message to be exact.
I’d suggest you create a dedicated query message to retrieve the GtETicketResponseBuyTicket1 instead, as that will decouple to logic of notifying something has happened (an event) from the request for data (a query).

Hope this helps you out!

Cheers,
Steven

Hi Steven,

you stated:
"... Are both present in the same class? If the answer is yes, than
that's the issue.
When dispatching a query, the QueryBus will select the first query
handler in a given Query Handling Component. ..."

Can you explain why this is implemented the way it is? It seems quite
a bit unintuitive at the first glance (it appears on the event
handling side there is a similiar mechanism used, where just one
handler per class gets called).

Regards,
Michael

Hi Michael,

Sure, I am fine with specifying that.
The Query Handler registration process is such that it will wrap a Method in an Axon specific MethodQueryMessageHandlerDefinition.
During this registration process, the handlers are assigned to the QueryBus which is present in your application.

The QueryBus has a Map to that end, where the key is the name of the Query and the value is a list of QuerySubscriptions.
The QuerySubscription in turn consists of the response type of the handler, and the MessageHandler itself.
Even further, the MessageHandler, contains the ‘target’ (the Object holding the Query Handler) and a Model based on the target.
Going back to the registration process, a Query Handler is only added to the List of QuerySubscriptions if it is not already present in that list.

Now, since the QuerySubscription is identical if (1) the Response Types are the same and (2) the QueryHandlers are the same, a second @QueryHandler annotated method with the same return type and query payload type in a given target will also be identical.
Hence, it will not be added to the registration to begin with.

In hindsight I should’ve added this to my initial response, as it suggests that both Query Handlers are registered.
This is thus however not how it is currently implemented.

Added though, I cant conceive of a use case where you’d have two @QueryHandler methods in one class, which both handle the same Query Type and return the same Query Response.
Would you be able to describe such a situation, Michael?

Hope this gives you guys some insights by the way!

Cheers,
Steven

Hi All,

Steven, many thanks for your time to clarify and the insights, though
I still don't quite understand why it is done that way - what's the
rationale behind it?

Not surprisingly, by design the query handlers used in scatter-gather
queries need to handle all the same query type (T) and they all need
to return the same response type (R) which is defined in the typing of
QueryMessage<T, R>. So, if i were to put more than one of these query
handlers into a class, they would have the same signature. Looking at
Axon's Query-API nothing is wrong with this approach - however, the
thing that really surprises is that the implementation doesn't account
for this (and I as a user cannot know that from looking at the API).

I'm not saying this is the default use case, but let's assume the
following simple example where you have different models from which
you want to extract some information as a query response, e.g.

class QueryHandler {
    @QueryHandler
    List<Answer> handleQueryForModel1(query, model1) {
        model1.findSomething(query).map(x -> transformModel1(x)).collect()
    }

    @QueryHandler
    List<Answer> handleQueryForModel2(query, model2) {
        model2.findSomethingSimiliar(query).limit(10).map(y ->
transformModel2(y)).collect()
    }
}

Why would I want to separate this? Axon injects dependencies through
the handler functions, so everything is nicely separated. The
surrounding class is just ceremony - it's stateless anyway; it's more
or less a namespace to keep a logical bound around those functions.

Regards,
Michael

Hi Michael,

once upon a time, we have decided to use the “invoke dynamic” semantics (as defined in the JVM specifications) for message handlers. This basically means that when finding a method to invoke, we pick the best matching method on any instance that matches the message that we’re sending to it.
We have had this in place for Commands and Events for a long time already (dating back to Axon 2), and didn’t change these semantics when we introduced Queries.

We do realize that for scatter-gather queries this may not always be expected. We might want to reconsider the behavior in that case, but it’s just how it currently works…

Cheers,