# A handler nothing subscribes to does nothing

> A passing unit test proves a handler works when called — not that anything calls it. If no subscription wires the handler to its event, the event fires and dies with no consumer. Assert the subscription, and choose sync versus async delivery on purpose.

URL: https://biloh.com.au/docs/engineering-notes/wiring-an-event-to-its-handler
Category: Engineering notes | Audience: builder | Updated: 2026-06-26

We had a handler that issued a branded invoice when a subscription payment came in. It was implemented. It was unit-tested. It had **never run in production** — because nothing subscribed it to its event. The event fired on every payment and died with no consumer; no invoice was ever issued.

The lesson is uncomfortable and worth internalising: **a green unit test on a handler proves the handler works when you call it, not that anything calls it.** The wiring — the subscription that connects an event type to a handler — is a separate fact that needs its own verification.

## How to verify the wiring, not just the logic

Write a test that drives the **real dispatch path**: emit the event the way production emits it, then assert the side effect actually happened — the row was written, the email was sent. If the subscription is missing, that test fails even though the handler's own unit test is green. That difference is the entire point: one test exercises the function, the other exercises the connection.

## Sync or async — decide on purpose

Once an event has a consumer, *how* it runs matters:

- **Synchronous** handlers run inline as the event is emitted. Choose this for a side effect that **must** happen with the triggering action and cannot tolerate a queue that might not drain — for example, issuing a financial document the moment money is received.
- **Asynchronous** handlers run later off a queue. Choose this for work that can lag a little — a notification email, a mirror to an external accounting system.

Defaulting everything to async is convenient until the queue stalls and a money-critical document silently never appears. Match the delivery mode to the cost of the side effect not happening.

## Related

- [When the money arrives but can't be recorded](/docs/engineering-notes/money-received-but-unrecorded)
- [Show the price you'll charge: one source of truth](/docs/engineering-notes/displayed-equals-charged)
