There is no universally
correct solution here, but we had a requirement to guarantee that by the
time we returned an "OK" response to the initial request from a client,
the query model had a record of the request already. (We had complaints
from clients who sent us a request and then immediately tried to query
its status and were alarmed that the query didn't return anything.)
Our solution was to prepopulate the query model before sending the
command to Axon and before replying to the client. The query model still
gets populated by event handlers too (otherwise we couldn't rebuild)
but the event handlers that update the query model are designed to
handle the case where the model is already up to date. In practice for
us, on PostgreSQL, that means having ON CONFLICT clauses on all our
INSERT statements.
For us the concern is only whether the record exists at all in the query
model; after that our application is fine with eventual consistency.
However, for the more general case, one option would be to update the
query model from your command handlers and make sure the command bus is
synchronous. At its simplest, this might look like
class SomeAggregate {
@CommandHandler
public void handle(SomeCommand command, QueryModelUpdater updater) {
SomeEvent event = doComputations(command);
updater.on(event);
apply(event);
}
}
class QueryModelUpdater {
@EventHandler
public void on(SomeEvent event) {
// do the equivalent of this with whatever database library you
use
UPDATE query_model SET field1 = event.getField1() WHERE id =
event.getId();
}
}
The downside is you'll double-update the query model; if that's a
nonstarter for performance reasons, you could add logic to detect
whether you're in an event replay, say, and skip the update if not.
Hope that's useful for you.
-Steve
September
1, 2017 at 7:56 AM