Command vs Event Handlers for dealing with external systems

Hi, I’m trying to figured out the best way to handle calling an external system. Everything I’ve read indicates that this is generally best handled in event handlers, but upon reflection it seems a bit contradictory. Let’s say I send a “BuyOrder” command that at some point needs to call a credit card processing gateway. It seems more ‘natural’ to handle the processing in the command handler, becuse the subsequent events would be based on say what happened during the processing (e.g. a OrderBought event, a CreditCardDeclined event etc). I’m not sure how to address this on the event side as it doesn’t seem correct to just handle the BuyOrder by directly ‘applying’ say an ‘OrderBought’ because it actually hasn’t happened yet.

What about naming “PlaceBuyOrder” and “BuyOrderPlaced” or “EnterBuyOrder” and “BuyOrderEntered” since really a “buy order” is a noun in most investing circles.

The advice is to call external services in event handlers. The reason is that command handling should generally perform as fast as possible. External services typically don’t guarantee anything.
The event handler would react on …RequestedEvent type events, and confirm/acknowledge them once the external service has responded.

That doesn’t mean you can’t call external services from your aggregate.

Cheers,

Allard

Good point :wink: Though this was more of a typical e-commerce cart-ish scenario

Hmm. Ok I think I’m following, but I thought, perhaps incorrectly that event handlers shouldn’t emit more events. So is something like the following ‘ok’?

class Order {

@CommandHandler
void purchase(command:PurchaseOrder) {

apply (PurchaseOrderRequested)

}

@EventHandler
void handle(PurchaseOrderRequested) {
//call external, then
apply(OrderPurchased)

  • or -
    apply(CreditCardDenied)
    }

}

Sorry, I wasn’t clear enough. With event handlers, I meant those outside of the aggregate. You’re right that an EventSourcingHandler (internal EventHandler) cannot generate more events.
Hope that makes more sense.

Cheers,

Allard

Ok so that same model would be ‘ok’ if it were more like this?

@Component
class Purchaser {
@EventHandler
void handle(PurchaseOrderRequested) {
//call external, then
apply(OrderPurchased)

  • or -
    apply(CreditCardDenied)
    }
    }

And that Purchaser would need to be ‘ReplayAware’ as well, in order to ignore events that do call out.

Hi Erich,

the Purchaser is in fact a Saga. Saga’s don’t always have to be implemented with Axon’s Saga support. In some cases, a singleton bean is just enough. In this case, there is not enough “process” to justify a full-blown saga.

However, Saga’s are not replayable, as they cause side-effects. So it is important that you never assign such a bean to a replayable cluster.

In your purchaser, you cannot apply events. Instead, you should send commands to confirm or reject a payment:

@Component
class Purchaser {

@EventHandler
void handle(PurchaseOrderRequested) {
//call external, then
commandGateway.send(… ConfirmOrderPurchase)

  • or -
    commandGateway.send(… RejectPurchaseOrder)
    }
    }

Cheers,

Allard

Ah ok, that’s much clearer :slight_smile: