In CQRS/ES, can a command create another command?

  softwareengineering

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.

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.

1

Recommended viewing: Udi Dahan on Reliable Messaging — it’s not quite what you are describing, but closely related.

Now, is it common practice for a command to not emit any events, but rather to enqueue another command?

I haven’t seen anybody recommending that practice.

Short answer: if you don’t save some state, then you can’t recover the enqueued command if you crash after acknowledging that you have received it.

If you decide that you need to save state, it’s not clear that there’s any great advantage to scheduling the second command from the first, rather than using an event handler.

You’ll get a system that is architecturally more loosely coupled if you only emit events from a command. Put another way, one command should not need to know what other external commands to issue; that should be the responsibility of the external party (who should subscribe to the event, and could be, as you mentioned, a saga manager having coordination responsibilities, or just another module that has dependency on those events).

LEAVE A COMMENT