In CQRS/ES, can a command create another command

command-messagecqrsdomain-driven-designevent-sourcing

In CQRS/ES, a command is sent from the client to the server and routed to the appropriate command handler. That command handler loads an aggregate from its repository, and calls some method on it, and saves it back to the repository. Events are generated. An event handler/saga/process manager can listen to these events in order to issue commands.

So, commands (input) produce events (output), which can then feed back into the system more commands (input). Now, is it common practice for a command to not emit any events, but rather to enqueue another command? Such an approach could be used to force execution in an external process.

EDIT:

The specific use case that I have in mind is the processing of payment details. The client submits a PayInvoice command, whose payload includes the user's credit card details. The PayInvoiceHandler passes a MakeInvoicePayment command to a separate process, which is responsible for interacting with the payment gateway. If the payment is successful, an InvoicePaid event is generated. If for some reason the system crashes after the PayInvoice command is persisted but before the MakeInvoicePayment command is persisted, we can track this manually (no payment will have gone through). If the system crashes after the MakeInvoicePayment command is persisted but before the InvoicePaid event is persisted, we may have a situation where the user's credit card is charged but the invoice is not flagged as having been paid. In that case, the situation would have to be manually investigated and the invoice manually marked as paid.

Best Answer

In retrospect, I think I was complicating the issue.

In general, commands should either throw an exception or raise one or more events.

If I could summarise the architecture of Event Sourcing it would be as follows:

  • Commands are inputs representing instructions to do something.
  • Events are outputs representing historical facts of what was done.
  • Event handlers can listen events in order to issue commands, helping coordinate the different parts of the system.

Having one command create another command causes ambiguity in the general meaning of commands and events: if one command "triggers" another command, it is implying that a command is "an historical fact of what was done". This contradicts the intent of these two types of messages, and could become a slippery path, in that other developers could trigger events from events, which could lead to corrupt data and eventual inconsistency.

In regards to the specific scenario I posed, the complicating factor was that I didn't want the main thread to interact with the payment gateway, as (being a persistent, single-threaded process), this would not allow other commands to be processed. The simple solution here is to spawn another thread/process to handle the payment.

To illustrate, the client sends a PayInvoice command. The PayInvoiceHandler starts a new process and passes it the payment details. The new process communicates with the payment gateway. If the payment was successful, it calls invoice.markAsPaid() with the receipt number (which produces the InvoicePaid event). If the payment was unsuccessful, it calls invoice.paymentFailed() with passes a reference code for further investigation (which produces the InvoicePaymentFailed event). So despite the fact that a separate process/thread is involved, the pattern remains Command -> Event.

In regards to failure, there are three scenarios, the system could crash after the PayInvoice command is persisted but before the InvoicePaid or InvoicePaymentFailed events are persisted. In this case, we don't know if the user's credit card was charged. In such a case, the user will notice the charge on their credit card and make a complaint, in which case a member of staff can investigate the issue and manually mark the invoice as paid.

Related Topic