Signals
Fenrir provides a signal system inspired by Blinker for event-driven programming. Signals allow decoupled components to notify each other when certain events occur.
signal() Function
The signal() function is the primary way to get or create a named signal on the global signal bus:
1 2 3 4 5 | |
If a signal with the given name already exists, it is returned. Otherwise a new Signal is created and registered on the global Namespace.
Namespace Class
Namespace is a dict subclass that holds named signals:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Signal Class
Signal objects represent individual event channels.
Signal.connect(receiver, sender=None, weak=True)
Connect a receiver function to the signal. The receiver is called with (sender, **kwargs) whenever the signal is sent. Returns the receiver so it can be used as a decorator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Signal.disconnect(receiver, sender=None)
Remove a previously connected receiver:
1 2 3 4 5 6 7 8 9 10 11 12 | |
Signal.send(sender=None, **kwargs)
Send the signal to all connected receivers. Returns a list of (receiver, result) pairs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Built-in Signals
Fenrir ships with four built-in signals:
| Signal | Description |
|---|---|
request_started |
Fires before each request is processed |
request_finished |
Fires after each request completes |
got_request_exception |
Fires when an unhandled exception occurs |
template_rendered |
Fires after a template is rendered |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
Async Receivers
Signals support both sync and async receiver functions. Async receivers are automatically scheduled as asyncio tasks when a running event loop is available:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Error Handling for Async Receivers
Exceptions raised by async receivers are logged and do not crash the application. If no event loop is running, async receivers are silently skipped:
1 2 3 4 5 6 7 8 9 10 11 | |
If an async receiver raises an exception, the _handle_signal_error callback logs it via logging.getLogger("fenrir.signals"). Sync receivers that raise exceptions propagate normally.
Signal API Reference
| Function / Class | Description |
|---|---|
signal(name, doc=None) |
Get or create a named signal on the global signal bus. Returns Signal. |
signal_bus |
The global Namespace instance holding all registered signals. |
Namespace.signal(name, doc=None) |
Create or get a named signal within a namespace. |
Signal.connect(receiver, sender=None, weak=True) |
Connect a receiver. Returns the receiver for use as a decorator. |
Signal.disconnect(receiver, sender=None) |
Remove a receiver from the signal. |
Signal.send(sender=None, **kwargs) |
Send the signal to all connected receivers. Returns List[Tuple[Callable, Any]]. |
request_started |
Built-in signal fired before each request. |
request_finished |
Built-in signal fired after each request. |
got_request_exception |
Built-in signal fired on unhandled exceptions. |
template_rendered |
Built-in signal fired after a template is rendered. |