feat(event-dispatcher): add async in-process event bus#12
Merged
Conversation
…in communication Implement EventDispatcher core module to decouple domain emitters from consumers, avoiding circular dependencies and growing coupling between domains (chatbot, ticket, live_chat). - EventDispatcher class with subscribe/publish using asyncio fire-and-forget tasks - @event_handler decorator with payload type validation and structured error logging - Typed Pydantic schemas for domain events - EVENT_PAYLOAD_MAP for compile-time wiring validation at startup - Custom exceptions: EventSchemaError, InvalidHandlerError - Singleton access via get_event_dispatcher (lru_cache) - Integration in app lifespan (main.py) with listener registration hook - Unit tests for dispatcher logic and decorator behavior - Module README and architectural docs (docs/event_dispatcher.md)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implement EventDispatcher core module to decouple domain emitters from consumers, avoiding circular dependencies and growing coupling between domains (chatbot, ticket, live_chat).
Summary
EventDispatcherinapp/core/event_dispatcher/to decouple cross-domain side effects (e.g. triage completion triggering ticket creation and conversation opening) without external infrastructure (Kafka, Redis, etc.)AppEventenum catalog for 6 domain events:triage.finished,ticket.created,ticket.assignee_updated,ticket.status_updated,ticket.escalated,ticket.closed@event_handlerdecorator validation andEVENT_PAYLOAD_MAPwiring — schema mismatches raiseInvalidHandlerErrorbefore the app serves trafficasyncio.Task(fire-and-forget) with structured exception logging, so a failing listener never blocks the emitter or other listenersmain.py) with aregister_app_events_listenershook ready for domain listenersMotivation
As business flows grow (triage → ticket → conversation → notification), injecting services across domains creates circular dependencies and violates domain boundaries. The dispatcher inverts this: emitters publish events without knowing who reacts, and new side effects are added by subscribing listeners — no changes to the originating service.
See docs/event_dispatcher.md for the architectural decision, event catalog, chained event flow, and usage guidelines.
Test plan
EventDispatcher.subscribeandpublish— valid handlers, duplicate subscription idempotency, payload type mismatch rejection@event_handlerdecorator — payload validation, error logging on handler failure, schema error propagationRegistering event listeners to EventDispatcher.🤖 Generated with Claude Code