Docs / Guides / Events & listeners

Platform 03 · Study guide

Events & listeners

Decouple side effects (emails, audits, cache busts) from core request code using a sync event bus.

What you will learn
  • How to define an Event and Listener
  • How dispatch order and stop() work
  • When to use events vs queue jobs

1. Setup

No extra package. Import from tpy.events anywhere (service layer is typical).

from tpy.events import Event, Listener, EventDispatcher

class OrderPlaced(Event):
    def __init__(self, order_id: str) -> None:
        super().__init__()
        self.order_id = order_id

class LogOrder(Listener):
    def handle(self, event: Event) -> None:
        assert isinstance(event, OrderPlaced)
        print("order", event.order_id)

bus = EventDispatcher()
bus.listen(OrderPlaced, LogOrder())
bus.listen(OrderPlaced, lambda e: print("also", e.order_id))
bus.dispatch(OrderPlaced("ord_1"))

2. How it works

  1. You create a typed Event subclass carrying payload fields.
  2. Listeners register with listen(EventType, listener).
  3. dispatch runs typed listeners in order, then wildcard "*" listeners.
  4. Call event.stop() inside a listener to halt remaining typed listeners.
  5. Exceptions fail-fast (they propagate to the caller).
APIUse when
listenRegister class or callable
dispatchNotify all listeners
dispatch_untilStop at first non-None return
forgetClear listeners for a type
Events are synchronous. For slow work (email SMTP, webhooks), dispatch an event that enqueues a Job — see the Queue guide.