Interview question
Are Django signal handlers executed synchronously or asynchronously? How do you handle this? Django signal handlers synchronously या asynchronously execute होते हैं? इसे कैसे handle करते हैं?
Answer
Signal handlers are executed synchronously in the same process, blocking the request. For long-running operations, use Celery tasks to execute asynchronously and avoid blocking.
| Approach | When | Pros/Cons |
|---|---|---|
| Synchronous (default) | Quick operations (cache updates) | Fast, but blocks request |
| Async with Celery | Long operations (emails, API calls) | Non-blocking, but complex |
| Threading | Background tasks | Simple but risky with ORM |
// ❌ SYNCHRONOUS - Blocks request
@receiver(post_save, sender=Book)
def send_email_on_save(sender, instance, created, **kwargs):
if created:
# This BLOCKS the request until email is sent
send_notification_email(instance.author_email)
print("Email sent") # Delays user response
// ✅ ASYNCHRONOUS - Celery Queue
from celery import shared_task
from django.db.models.signals import post_save
@receiver(post_save, sender=Book)
def trigger_email_task(sender, instance, created, **kwargs):
if created:
# Queue task for async execution
send_email_task.delay(instance.id)
@shared_task
def send_email_task(book_id):
book = Book.objects.get(id=book_id)
send_notification_email(book.author_email)
// ✅ SEMI-SYNC - Threading (light workload)
import threading
@receiver(post_save, sender=Book)
def async_logging(sender, instance, created, **kwargs):
def log_in_background():
AuditLog.objects.create(
action="created" if created else "updated",
model="Book",
instance_id=instance.id
)
thread = threading.Thread(target=log_in_background)
thread.daemon = True
thread.start()
// Signal Handler Timing Example
import time
@receiver(post_save, sender=Book)
def slow_handler(sender, instance, created, **kwargs):
start = time.time()
time.sleep(5) # Simulates slow operation
duration = time.time() - start
print(f"Handler took {duration} seconds - USER WAITED THIS LONG!")
// Measure Impact
from django.test import TestCase
import time
class SignalPerformanceTest(TestCase):
def test_save_speed(self):
start = time.time()
Book.objects.create(title="Test", author="Test")
duration = time.time() - start
print(f"Save took {duration} seconds")
# With async: ~0.01 seconds
# With sync email: ~2 seconds (blocked)
// Best Practice - Use Celery for Heavy Operations
from celery import shared_task
@receiver(post_save, sender=Book)
def handle_book_creation(sender, instance, created, **kwargs):
if created:
# Quick operations in signal
cache.set(f"book_{instance.id}", instance)
# Heavy operations to Celery
process_book_async.delay(instance.id)
@shared_task
def process_book_async(book_id):
book = Book.objects.get(id=book_id)
# Send notifications
send_email_task(book)
# Process images
generate_thumbnails(book)
# Update search index
update_search_index(book)Signal handlers synchronously execute होते हैं - request को block करते हैं। Heavy operations के लिए Celery use करो।
| Approach | कब | Pros/Cons |
|---|---|---|
| Synchronous | Quick operations | Fast, blocks request |
| Celery Async | Heavy operations | Non-blocking, complex |
// ❌ Synchronous - blocks
@receiver(post_save, sender=Book)
def send_email(sender, instance, created, **kwargs):
if created:
send_notification(instance.email)
# User इंतज़ार करता है
// ✅ Async with Celery
from celery import shared_task
@receiver(post_save, sender=Book)
def trigger_email(sender, instance, created, **kwargs):
if created:
send_email_async.delay(instance.id)
@shared_task
def send_email_async(book_id):
book = Book.objects.get(id=book_id)
send_notification(book.email)Was this answer clear?