CQRS – Does It Need to Be Fire and Forget for Read Guarantees?

cqrsdomain-driven-designevent-sourcingread-model

I'm in researching phase of CQRS+ES. Never done in real world yet. But very soon.

However what I saw in StackOverflow and projects, CQRS seems to be fire and forget.

So what if there is a chain command which need result from another command.

First example, reward management and account management bounded contexts

  1. Application layer send GiveReward command to reward management

  2. Reward management fire a CreateTransaction command to account bounded context, And get the result as TransactionID(GUID).
    Refer to this answer, I can get the TransactionID while CQRS was fire and forget

  3. Reward management need to use some data of that transaction by query it from account management using TransactionID before fire next event.

Here how can I guarantee account management has finish creating read model, So that reward management can read it?

Second example, Rest API to open a Gacha box.

  1. User call this api.

  2. Application layer send OpenGacha command.

  3. Business layer fire and forget GachaOpenedEvent.

How can rest api guarantee OpenGachaEvent has created the read model?

These scenario lead me to a question,

Does CQRS need to be fire and forget, If we need to read guarantee after command?

Any others solution to solve this problem?

Best Answer

One way to view CQRS is that it's commands (messages) all the way down.

Taking your example:

  1. Application layer send GiveReward command to reward management with a correlation ID.
  2. Reward management fires a CreateTransaction command to the account bounded context, with the Correlation ID included.
  3. CreateTransaction finishes and broadcasts a TransactionCompleted event with the correlation ID.
  4. The Application Layer listens to TransactionCompleted events and connects it back to the original request through the correlation ID.

For your web front-end you can extend this approach to there as well. E.g. in a react/redux approach the command is relayed to the server, which eventually updates the redux store over a websocket feed which relays GiveRewardCompleted events.

Other approaches are returning the correlation ID to the front-end and have it poll the server for updates, or block at the server edge until a TransactionCompleted message is received.