Asynchronous Dispatching¶
The AsyncEventDispatcher class provides asynchronous event dispatching using async/await. Use this when your listeners perform async operations.
When to Use AsyncEventDispatcher¶
Choose AsyncEventDispatcher when:
Your listeners perform async I/O operations (database queries, HTTP requests, file operations)
You’re working in an async/await application
You want non-blocking event handling
You need to coordinate multiple async operations
Creating an Async Dispatcher¶
Create an instance of AsyncEventDispatcher:
from whistle import AsyncEventDispatcher
dispatcher = AsyncEventDispatcher()
All listeners registered with this dispatcher must be async functions (coroutines). Attempting to register a regular function will raise a TypeError.
Basic Async Dispatching¶
Here’s a simple async example:
import asyncio
from whistle import AsyncEventDispatcher
async def main():
"""Demonstrate basic asynchronous event dispatching."""
# Create an async event dispatcher
dispatcher = AsyncEventDispatcher()
# Define an async listener function
async def on_data_received(event):
# Simulate async operation
await asyncio.sleep(0.01)
print(f"Data received for event: {event.name}")
# Register the async listener
dispatcher.add_listener("data.received", on_data_received)
# Dispatch the event asynchronously
await dispatcher.adispatch("data.received")
if __name__ == "__main__":
asyncio.run(main())
Key differences from synchronous dispatching:
Listeners are defined with
async defListeners can use
awaitfor async operationsEvents are dispatched with
await dispatcher.adispatch()The entire workflow must run in an async context (
asyncio.run())
Async I/O Operations¶
The real power of AsyncEventDispatcher comes from coordinating async I/O:
import asyncio
from whistle import AsyncEventDispatcher
async def main():
"""Demonstrate async event dispatching with simulated I/O operations."""
dispatcher = AsyncEventDispatcher()
# Simulate async database write
async def save_to_database(event):
print("Saving to database...")
await asyncio.sleep(0.02) # Simulate I/O delay
print("Database save complete")
# Simulate async API call
async def notify_external_service(event):
print("Notifying external service...")
await asyncio.sleep(0.01) # Simulate network delay
print("External service notified")
# Register async listeners
dispatcher.add_listener("order.created", save_to_database)
dispatcher.add_listener("order.created", notify_external_service)
# Dispatch event - listeners execute sequentially with async/await
print("Order created, processing...")
await dispatcher.adispatch("order.created")
print("All async operations complete")
if __name__ == "__main__":
asyncio.run(main())
This example simulates database writes and API calls. Each listener can perform async operations, but they execute sequentially (one after another, not concurrently).
Key Differences from EventDispatcher¶
Type Safety¶
AsyncEventDispatcher enforces async listeners:
dispatcher = AsyncEventDispatcher()
# This works - async function
async def async_listener(event):
await some_async_operation()
dispatcher.add_listener("event", async_listener) # ✓
# This raises TypeError - sync function not allowed
def sync_listener(event):
some_sync_operation()
dispatcher.add_listener("event", sync_listener) # ✗ TypeError
Dispatch Method¶
AsyncEventDispatcher only supports async dispatching:
adispatch(event_id, event=None): Async dispatch (use this)dispatch(event_id, event=None): RaisesNotImplementedError
You must use await dispatcher.adispatch() - the synchronous dispatch() method is not implemented.
Sequential Execution¶
Important: Listeners execute sequentially, not concurrently. Each listener completes before the next begins:
@dispatcher.listen("event")
async def first(event):
await asyncio.sleep(1) # Takes 1 second
print("First done")
@dispatcher.listen("event")
async def second(event):
await asyncio.sleep(1) # Takes 1 second
print("Second done")
await dispatcher.adispatch("event") # Takes 2 seconds total
If you need concurrent execution, dispatch multiple events concurrently or use asyncio.gather() within a listener.
API Summary¶
AsyncEventDispatcher provides:
add_listener(event_id, listener, priority=0): Register an async listenerremove_listener(event_id, listener): Unregister a listenerlisten(event_id, priority=0): Decorator for registering listenersadispatch(event_id, event=None): Trigger an event asynchronouslyget_listeners(event_id=None): Retrieve registered listenershas_listeners(event_id=None): Check if listeners are registered
See also Synchronous Dispatching for the sync equivalent.