DEV Community

Andrei Koptev
Andrei Koptev

Posted on • Edited on

Making Django's Signals Async with Celery

Prepare

  • Django project with long-task logic
  • Celery with any backend

For example: send push after any event or auth user through sms code or email link.

Mark: to sign-in/sign-up users via SMS you may use this library

Problems

  • Django signals synchronous by default
  • We must to wait when transaction completed
  • Clients can to wait response for a long time

Short description

  • Configure celery
  • Create application (for example, notifier)
  • Configure post_save signal through celery task
  • Configure AppConfig to load function

Detail

  1. Create notifier application
  2. Add tasks.py
tasks.py

import uuid
from collections import namedtuple
from django.db.models.signals import post_save
from run_celery import app

from some_apps.models import SomeModel1, SomeModel2, SomeModel3

Ctx = namedtuple('Ctx', 'class_name identifier')

models = [
  SomeModel1, 
  SomeModel2, 
  SomeModel3
]


def register_models():
    for model in models:
        post_save.connect(_post_save,
                          sender=model,
                          dispatch_uid=uuid.uuid4())


def _post_save(sender, instance, **kwargs):
    ctx = Ctx(class_name=instance.__class__.__name__,
                        identifier=instance.pk)
    _async_post_save_handler.delay(ctx)


@app.task
def _async_post_save_handler(ctx: Ctx):
    """
    Get model and instance from notifier object and then make
    some other logic
    """
  ...
Enter fullscreen mode Exit fullscreen mode

Finally, add to apps.py:


from django.apps import AppConfig


class NotifierConfig(AppConfig):
    name = 'notifier'

    def ready(self):
        from apps.notifier.tasks import register_models
        register_models() # here!
Enter fullscreen mode Exit fullscreen mode

Save and run Django and run celery.

Conclusion

  • celery help you create async handlers to your Django models
  • Solution is great to separate post_save and async logic

Thanks for reading

Top comments (2)

Collapse
 
junihoj profile image
Eze Onyekachukwu

thanks a lot for this wonderful tips.... can I see what run_celery looks like??

Collapse
 
anilnarisetti profile image
Anil Narisetti

AppRegistryNotReady("Apps aren't loaded yet.")