DRAFTThis page is not published. Only visible in development mode.

Handlers

A handler binds a block of statements to one variant of an event. When that variant is dispatched, every subscribed handler runs synchronously, inside the dispatching transaction. Handlers are how one domain event fans out into independent reactions without the caller knowing about any of them.

Several handlers, one event

Start with an event and the state the reactions will touch. Run the snippets on this page in order:

$ An Event and the Tables Handlers Will Write
$ ctrl+enter to run

Each handler is an independent concern - here one records an audit entry while another tracks revenue. Payload fields are available in the body with an event_ prefix (amount becomes event_amount). The dispatch reports how many handlers ran:

$ Several Handlers, One Variant
$ ctrl+enter to run

Adding a third reaction later means adding a handler - the dispatching code does not change. Both effects are already committed:

$ Each Handler Did Its Own Work
$ ctrl+enter to run

Bodies are scripts

A handler body is not limited to a single statement - it is ReifyDB Scripting, with variables, control flow, and any number of reads and writes, just like a procedure body:

$ Handler Bodies Are Scripts
$ ctrl+enter to run
$ Read the Computed Result
$ ctrl+enter to run

Chained dispatch

A handler can itself dispatch, so one domain event can trigger the next stage of a process. The whole chain executes in the original transaction: either everything commits or nothing does. Note that handlers_fired counts the handlers of the dispatched variant itself - three are now subscribed to OrderPlaced:

$ Handlers Can Dispatch Further Events
$ ctrl+enter to run

The audit trail shows the full story: this page dispatched OrderPlaced twice (two placed entries), and the chained OrderShipped handler wrote shipped:

$ The Whole Chain Committed Together
$ ctrl+enter to run

Lifecycle

Handlers are catalog objects: drop handler unsubscribes one without touching the event or the other handlers, and system::handlers lists what is currently bound:

$ Drop a Handler
$ ctrl+enter to run
$ Dispatch Reflects the Remaining Handlers
$ ctrl+enter to run

Handler, view, or subscription?

  • --Derived state that must track its sources: a view - declarative and impossible to forget.
  • --Pushing changes out to connected clients: a subscription.
  • --Imperative side effects of a named domain event, atomic with the event itself: a handler.
Synchronous and transactional
Handlers never run in the background. If a handler fails, the dispatching transaction fails with it - which is exactly what you want when the reaction is part of the operation's correctness.