BudiBadu Logo
Samplebadu

Flask by Example: Signal Receiver Hooks

Flask 3.0+

Signals allow you to decouple your application logic by subscribing to events. This example shows how to use the `blinker` library to listen for Flask's built-in signals.

Code

from flask import Flask, template_rendered, request_started
from flask.signals import Namespace

app = Flask(__name__)

# 1. Listen to Built-in Signals
def log_template_renders(sender, template, context, **extra):
    print(f"Rendering template: {template.name}")
    # You could log this to a database or analytics service

# Connect the receiver function to the signal
template_rendered.connect(log_template_renders, app)

# 2. Define Custom Signals
my_signals = Namespace()
user_registered = my_signals.signal('user-registered')

def send_welcome_email(sender, user_email, **extra):
    print(f"Sending welcome email to {user_email}...")

# Connect custom signal
user_registered.connect(send_welcome_email)

@app.route('/register/<email>')
def register(email):
    # Perform registration logic...
    
    # 3. Send the signal
    user_registered.send(app, user_email=email)
    
    return f"Registered {email}"

Explanation

Signals allow different parts of your application to communicate without being tightly coupled. Flask comes with several built-in signals, such as template_rendered or request_started, which you can subscribe to. This is useful for logging, analytics, or debugging, as you can "hook" into these events without modifying the core application code.

You can also define your own custom signals using the blinker library (which Flask uses internally). For example, you might define a user_registered signal that triggers a welcome email. The registration route simply sends the signal, and a separate receiver function handles the email logic.

This separation of concerns makes your code cleaner and easier to maintain. The registration logic doesn't need to know about email servers or logging systems; it just announces that an event happened, and any interested subscribers can react accordingly.

Code Breakdown

7
Receiver functions must accept sender and **extra arguments. The sender is usually the application instance or the object triggering the event.
12
template_rendered.connect(func, app) subscribes your function to the signal. Passing app as the second argument ensures you only receive signals from that specific application instance.
29
user_registered.send() triggers the event. All connected functions are executed synchronously, so be careful not to put slow operations (like sending real emails) directly in the receiver without using a task queue.