Event Handler¶
An Event Handler is a piece of behavior that reacts to an Event by causing a side effect outside the model – sending an email, calling an external API, writing to a log, pushing a notification.
An Event Handler is not an Aggregate (it owns no state and produces no Events of its own), and it is not a Policy (it does not derive Commands from Events). It is the integration boundary of the model: the place where the inside of the system meets the outside.
Event Handler vs. Policy¶
The boundary between an Event Handler and a Policy is the kind of effect they cause.
A Policy stays inside the model. It reacts to an Event by emitting a Command, which lands on an Aggregate, which produces another Event. The whole chain is observable in the model.
An Event Handler exits the model. It reacts to an Event by sending an email or calling a service, and the outcome of that effect is not part of the Event sequence. If you need to react to the result of an external call (the email bounced, the service returned an error), you typically wrap the integration in an External System and let it produce its own Events back into the model.
Idempotency Matters¶
Because an Event Handler causes side effects in the world, the question of what happens if the same Event is delivered twice? matters more for handlers than for any other kind. An Event Handler that sends the same email twice is rarely what you want. ESDM lets you declare the consumer's delivery guarantee – at-least-once or at-most-once – and the linter checks for the combinations that lead to bugs.
A Handler Is Not Free¶
Modeling integrations as Event Handlers makes them visible. It also makes them part of the model the linter validates. If a handler refers to an Event that doesn't exist, the linter catches it. If an Event has no consumer, the linter notices. These are exactly the corners where integrations rot first; making them visible is the point.