title |
class |
highlighter |
transition |
mdc |
monaco |
themeConfig |
addons |
Empowering Django with Background Workers |
text-center |
shiki |
slide-left |
true |
false |
|
|
Empowering Django with Background Workers
Jake Howard
- Senior Systems Engineer @ Torchbox
- Security & Performance @ Wagtail
- theorangeone.net
- @RealOrangeOne
- @RealOrangeOne
- @jake@theorangeone.net
layout: center
Django isn't just for websites
flowchart LR
U(User 🧑💻)
D[\Django/]
U---->|Request|D
D---->|Response|U
layout: full
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
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
flowchart LR
D[\Django/]
S[(Queue Store)]
R1{Runner}
R2{Runner}
R3{Runner}
D<--->S<-..->R1 & R2 & R3
layout: cover
When?
layout: fact
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
Celery!
Others...
Celery
- arq
- Django DB Queue
- Django Lightweight Queue
- Django Too Simple Q
- Django-Q
- Django-Q2
- Dramatiq
- Huey
- RQ
- Taskiq
- ...
Email
layout: none
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
```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*:
django.tasks
*
- API contract between library and application developers
- Swappable backends through
settings.py
- Built in backends:
- Django 5.2 🤞
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
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
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]
)
# 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
Q: Why something built-in?
- Improve interoperability
- Reduce cognitive load
- Reduce barrier to entry
layout: center
transition: fade
{.max-h-48.mx-auto}
vs
{.max-h-32.mx-auto}
layout: center
{.max-h-48.mx-auto}
vs
{.max-h-32.mx-auto}
layout: section
Where are we now?
pip install django-tasks
layout: section
Where will we be soon™?
Is this the end?
Out of scope
- Completion / failed hooks
- Bulk queueing
- Automated task retrying
- Task runner API
- Unified observability
- Cron-based scheduling
- Task timeouts
- Swappable argument serialization
The future is bright
layout: section
What's next?
layout: end
QUESTIONS?