--- title: Empowering Django with Background Workers class: text-center highlighter: shiki transition: slide-left mdc: true monaco: false themeConfig: primary: '#0c4b33' addons: - "slidev-addon-qrcode" --- # Empowering Django with Background Workers ### Jake Howard{.mt-10}
--- layout: center --- # Django isn't _just_ for websites ```mermaid flowchart LR U(User πŸ§‘β€πŸ’») D[\Django/] U---->|Request|D D---->|Response|U ``` --- layout: full --- ```mermaid flowchart BT U[User πŸ§‘β€πŸ’»] D[\Django/] DB[(Database)] C[(Cache)] E>Email] EA[External API] V[[Video Transcode]] ML((Machine Learning)) U---->|Request|D D---->|Response|U D-.-DB & E & EA & V & ML & C ``` --- layout: full --- ```mermaid flowchart BT U[User πŸ§‘β€πŸ’»] D[\Django/] DB[(Database)] C[(Cache)] E>Email] EA[External API] V[[Video Transcode]] ML((Machine Learning)) B{{Background Processing}} U--->|Request|D D--->|Response|U D---B D-.-C & DB B---E & V & ML & EA B---C & DB ``` --- layout: cover --- # Background Workers? --- layout: fact --- ```mermaid flowchart LR D[\Django/] S[(Queue Store)] R1{Runner} R2{Runner} R3{Runner} D<--->S<-..->R1 & R2 & R3 ``` --- layout: cover --- # When? --- layout: fact --- ```mermaid flowchart BT D[\Django/] subgraph Fast & Reliable DB[(Database)] C[(Cache)] end subgraph Slow / Unreliable E>Email] EA[External API] V[[Video Transcode]] ML((Machine Learning)) end D---DB & C D-.-E & EA & V & ML ``` --- layout: cover --- # Background Workers _in Django_ --- layout: cover background: https://docs.celeryq.dev/en/stable/_static/celery_512.png --- # Celery! --- layout: image-right image: https://images.unsplash.com/photo-1444703686981-a3abbc4d4fe3?q=80&w=1740&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D --- # Others... - ~~Celery~~ - arq - Django DB Queue - Django Lightweight Queue - Django Too Simple Q - Django-Q - Django-Q2 - Dramatiq - Huey - RQ - Taskiq - ... --- layout: cover background: https://images.unsplash.com/photo-1522096823084-2d1aa8411c13?q=80&w=1740&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D --- # Email --- layout: none --- ```python {all|18|19|10|11-16|all|18-19|all} from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string import django_rq from wagtail.models import Page def send_email_to_user(page: Page, user: User): email_content = render_to_string("notification-email.html", {"user": user, "page": page}) send_mail( subject="A page has been published", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) for user in page.subscribers.iterator(): django_rq.enqueue(send_email_to_user, user) ``` --- layout: center --- # A problem ````md magic-move ```python from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string import django_rq from wagtail.models import Page def send_email_to_user(page: Page, user: User): email_content = render_to_string("notification-email.html", {"user": user, "page": page}) send_mail( subject="A page has been published", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) for user in page.subscribers.iterator(): django_rq.enqueue(send_email_to_user, user) ``` ```python {all|7-9,20|all} from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string from wagtail.models import Page from my_celery_config import app @app.task def send_email_to_user(page: Page, user: User): email_content = render_to_string("notification-email.html", {"user": user, "page": page}) send_mail( subject="A page has been published", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) for user in page.subscribers.iterator(): send_email_to_user.delay(user) ``` ```` --- layout: fact --- # Situation: ## There are _14_ competing standards. --- layout: image image: /ridiculous.png class: bg-top! --- # Ridiculous! --- layout: fact --- ## Introducing*:{.mb-5} # `django.tasks`*
--- layout: image-right image: https://images.unsplash.com/photo-1674027444485-cec3da58eef4?q=80&w=1932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D class: flex items-center text-xl --- - API contract between library and application developers - Swappable backends through `settings.py` - Built in backends: - ORM - "Immediate" - "Dummy" - Django 5.2 🀞 - Backport for 4.2+ --- layout: center --- ````md magic-move ```python from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string from wagtail.models import Page from my_celery_config import app @app.task def send_email_to_user(page: Page, user: User): email_content = render_to_string("notification-email.html", {"user": user, "page": page}) send_mail( subject="A page has been published", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) for user in page.subscribers.iterator(): send_email_to_user.delay(user) ``` ```python {all|7-9,20|all} from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string from wagtail.models import Page from django.tasks import task @task() def send_email_to_user(page: Page, user: User): email_content = render_to_string("notification-email.html", {"user": user, "page": page}) send_mail( subject="A page has been published", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) for user in page.subscribers.iterator(): send_email_to_user.enqueue(user) ``` ```` --- layout: center --- ```python from django.contrib.auth.models import User from django.core.mail import send_mail from django.template.loader import render_to_string email_content = render_to_string("email-template.html", {"page": page}) for user in page.subscribers.iterator(): send_mail( subject="The page has changed", message=email_content from_email=None, # Use the default sender email recipient_list=[user.email] ) ``` ```python # settings.py EMAIL_BACKEND = "django.core.mail.backends.tasks.SMTPEmailBackend" ``` --- layout: image-right image: /soon.png class: flex justify-center text-2xl flex-col --- # Q: Why something new? ### A: It doesn't have to be --- layout: image-right image: https://images.unsplash.com/photo-1525683879097-8babce1c602a?q=80&w=1335&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D class: flex justify-center text-2xl flex-col --- # Q: Why something built-in? - Improve interoperability - Reduce cognitive load - Reduce barrier to entry --- layout: center transition: fade --- ![](/postgres.png){.max-h-48.mx-auto} ## vs ![](https://docs.celeryq.dev/en/stable/_static/celery_512.png){.max-h-32.mx-auto} --- layout: center --- ![](/postgres.png){.max-h-48.mx-auto} ## vs ![](/elasticsearch.png){.max-h-32.mx-auto} --- layout: section --- # Where are we now? ## `pip install django-tasks` --- layout: section --- # Where will we be soonβ„’? --- layout: cover background: https://docs.celeryq.dev/en/stable/_static/celery_512.png --- # Is this the end? --- layout: image-right image: https://images.unsplash.com/photo-1451187580459-43490279c0fa?q=80&w=1744&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D class: flex justify-center flex-col text-xl --- # Out of scope - Completion / failed hooks - Bulk queueing - Automated task retrying - Task runner API - Unified observability - Cron-based scheduling - Task timeouts - Swappable argument serialization --- layout: cover background: https://images.unsplash.com/photo-1519187903022-c0055ec4036a?q=80&w=1335&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D --- # The future is bright --- layout: section --- # What's next? --- layout: end --- QUESTIONS?