Django en Celery: Asynchrone Taakverwerking en Sollicitatievragen 2026

Leer Django en Celery configureren voor asynchrone taakverwerking met codevoorbeelden, task routing, Celery Beat, productie-instellingen en sollicitatievragen voor 2026.

Django en Celery asynchrone taakverwerking tutorial

Django en Celery vormen de ruggengraat van asynchrone taakverwerking in Python-webapplicaties. Nu Celery 5.6 en Django 6.0 beide ingrijpende updates bevatten in 2026, blijft kennis van gedistribueerde taakwachtrijen een cruciale vaardigheid voor backend-sollicitaties en productiesystemen.

Kernprincipe

Celery ontkoppelt tijdrovende operaties van de request-response cyclus. Een Django-view verstuurt een taak naar een message broker (Redis of RabbitMQ), waarna een apart workerproces deze asynchroon uitvoert. Dit patroon is geschikt voor het verzenden van e-mails, het genereren van rapporten, beeldverwerking en elke workload die anders de gebruiker zou blokkeren.

Hoe Celery integreert met Django

Celery draait als een onafhankelijk proces dat de codebase van het Django-project deelt. De integratie steunt op drie componenten: de Django-applicatie (producer), een message broker (Redis of RabbitMQ) en een of meerdere Celery workers (consumers). Wanneer een Django-view .delay() of .apply_async() aanroept, wordt de taak geserialiseerd en naar de brokerwachtrij gestuurd. Een worker pikt de taak op en voert de functie uit in een eigen proces.

De configuratie begint met een celery.py-module in de root van het Django-project:

python
# myproject/celery.py
import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

De aanroep autodiscover_tasks() scant elke geinstalleerde Django-app op een tasks.py-module en registreert alle gedecoreerde functies automatisch als Celery-taken.

In settings.py worden de broker en result backend geconfigureerd:

python
# myproject/settings.py
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'

Redis dient in de meeste Django-deployments als zowel broker als result backend. RabbitMQ blijft de betere keuze voor applicaties die quorum queues of geavanceerde routing vereisen, een functionaliteit die volledig wordt ondersteund sinds Celery 5.5.

Taken schrijven en versturen

Een Celery-taak is een reguliere Python-functie die is gedecoreerd met @shared_task. De shared_task-decorator voorkomt het hardcoden van de Celery app-instantie, waardoor de taak herbruikbaar is in verschillende Django-apps.

python
# orders/tasks.py
from celery import shared_task
from django.core.mail import send_mail
from orders.models import Order

@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_order_confirmation(self, order_id: int) -> str:
    """Send confirmation email for a completed order."""
    try:
        order = Order.objects.select_related('user').get(id=order_id)
        send_mail(
            subject=f'Order #{order.id} Confirmed',
            message=f'Your order totaling {order.total} has been confirmed.',
            from_email='noreply@example.com',
            recipient_list=[order.user.email],
        )
        return f'Email sent for order {order_id}'
    except Order.DoesNotExist:
        return f'Order {order_id} not found'
    except Exception as exc:
        # Retry on transient failures (SMTP timeout, etc.)
        raise self.retry(exc=exc)

Drie kritieke patronen zijn hier zichtbaar. Ten eerste geeft bind=True de taak toegang tot self, wat retries mogelijk maakt. Ten tweede ontvangt de functie een order_id integer in plaats van een ORM-object — modelinstanties kunnen niet betrouwbaar worden geserialiseerd over procesgrenzen heen. Ten derde plaatst self.retry(exc=exc) de taak opnieuw in de wachtrij met exponential backoff bij tijdelijke fouten.

Het versturen vanuit een Django-view:

python
# orders/views.py
from orders.tasks import send_order_confirmation

def complete_order(request, order_id):
    # ... process payment, update order status ...
    send_order_confirmation.delay(order_id)
    return redirect('order_success', order_id=order_id)

De .delay()-aanroep keert onmiddellijk terug. De gebruiker ziet de succespagina terwijl de e-mailtaak op de achtergrond wordt uitgevoerd.

Task Routing en Wachtrijbeheer

Productiesystemen dienen nooit alle taken in een enkele standaardwachtrij te plaatsen. Een trage rapportgeneratietaak kan snelle notificatietaken uithongeren wanneer ze dezelfde worker pool delen. Celery lost dit op met task routing.

python
# myproject/settings.py
CELERY_TASK_ROUTES = {
    'orders.tasks.send_order_confirmation': {'queue': 'notifications'},
    'reports.tasks.generate_monthly_report': {'queue': 'reports'},
    'images.tasks.resize_upload': {'queue': 'media'},
}

Workers worden vervolgens per wachtrij opgestart:

bash
# Start notification worker (fast tasks, high concurrency)
celery -A myproject worker -Q notifications -c 8 --loglevel=info

# Start report worker (slow tasks, limited concurrency)
celery -A myproject worker -Q reports -c 2 --loglevel=info

# Start media worker (CPU-bound, prefork pool)
celery -A myproject worker -Q media -c 4 -P prefork --loglevel=info

Deze scheiding voorkomt resource-conflicten. Notificatie-workers verwerken een hoog volume met 8 gelijktijdige threads, terwijl rapportage-workers slechts 2 gelijktijdige taken uitvoeren om geheugenuitputting bij zware databasequeries te voorkomen.

Klaar om je Django gesprekken te halen?

Oefen met onze interactieve simulatoren, flashcards en technische tests.

Periodieke taken met Celery Beat

Celery Beat is de ingebouwde scheduler voor terugkerende taken. Het draait als een apart proces dat taken op geconfigureerde intervallen naar de broker stuurt.

python
# myproject/settings.py
from celery.schedules import crontab

CELERY_BEAT_SCHEDULE = {
    'cleanup-expired-sessions': {
        'task': 'accounts.tasks.cleanup_expired_sessions',
        'schedule': crontab(hour=3, minute=0),  # Daily at 3 AM UTC
    },
    'sync-inventory': {
        'task': 'inventory.tasks.sync_external_inventory',
        'schedule': 300.0,  # Every 5 minutes
    },
    'generate-weekly-digest': {
        'task': 'notifications.tasks.send_weekly_digest',
        'schedule': crontab(hour=9, minute=0, day_of_week='monday'),
    },
}

Beat wordt naast de worker opgestart:

bash
celery -A myproject beat --loglevel=info

Een veelvoorkomende productiefout: het draaien van meerdere Beat-instanties veroorzaakt dubbele taakuitvoering. Er mag slechts een Beat-proces per deployment actief zijn. Tools zoals django-celery-beat slaan schedules op in de database, waardoor runtime-aanpassingen via de Django-admin mogelijk worden.

Monitoring en Observability met Flower

Flower biedt een real-time webdashboard voor het monitoren van Celery workers, taken en wachtrijen. Het toont succespercentages, uitvoeringstijden, wachtrijdieptes en workerstatus.

bash
# Install and run Flower
pip install flower
celery -A myproject flower --port=5555

In productieomgevingen dienen Flower-metrics te worden doorgestuurd naar een alerteringssysteem. Een groeiende wachtrijdiepte met vastgelopen taken wijst op capaciteitsproblemen bij de workers. Hoge retry-percentages op specifieke taken duiden op instabiliteit van externe services.

Celery 5.6 introduceert daarnaast verbeteringen in gestructureerde logging die integreren met JSON log-aggregatiesystemen zoals Datadog of ELK-stacks, wat volgens de release notes leidt tot effectievere debugging.

Django 6.0 Ingebouwde Taken vs. Celery

Django 6.0 bevat een native background tasks framework, wat de vraag oproept of Celery nog noodzakelijk is. Het antwoord hangt af van de use case.

Het ingebouwde takenframework van Django verwerkt eenvoudige achtergrondoperaties — e-mails versturen, caches legen, lichte dataverwerking — zonder dat een aparte broker-infrastructuur vereist is. De task runner is ingebouwd in Django zelf.

Celery blijft onmisbaar voor:

  • Gedistribueerde verwerking over meerdere machines
  • Prioriteitswachtrijen en task routing
  • Rate limiting en geavanceerde retry-strategieen
  • Periodieke scheduling (Celery Beat)
  • Resultaatopslag met configureerbare backends
  • Canvas workflows (chains, groups, chords) voor complexe taakorkestratie

Voor applicaties die uitsluitend fire-and-forget achtergrondwerk nodig hebben, vermindert de ingebouwde oplossing van Django 6.0 de operationele complexiteit. Voor alles wat gedistribueerde workers, scheduling of taakcompositie betreft, blijft Celery 5.6 de bewezen keuze.

Sollicitatievragen: Django en Celery

Technische sollicitaties voor backend-functies toetsen regelmatig kennis van Celery. Hieronder staan vragen die voortkomen uit daadwerkelijke Django-sollicitatiegespreken bij bedrijven varierend van startups tot FAANG.

Vraag: Waarom dienen taken primary keys te ontvangen in plaats van modelinstanties?

Django-modelinstanties bevatten databaseverbindingen, querysets en lazy-loaded relaties die serialisatie niet overleven. Het doorgeven van een order_id in plaats van een Order-object garandeert dat de taak verse data uit de database ophaalt, waardoor verouderde state en serialisatiefouten worden voorkomen.

Vraag: Hoe verschilt self.retry() van het handmatig opnieuw dispatchen van de taak?

self.retry() behoudt de retry-teller, past de geconfigureerde max_retries-limiet toe en gebruikt standaard exponential backoff. Het handmatig aanroepen van .delay() creert een volledig nieuwe taak met een gereset retry-teller, wat kan leiden tot oneindige retry-loops bij persistente fouten.

Vraag: Wat gebeurt er wanneer een Celery worker crasht midden in een taak?

Het gedrag hangt af van de acks_late-instelling. Met acks_late=True levert de broker het bericht opnieuw af bij een andere worker, aangezien de acknowledgment nooit is verzonden. Bij de standaardinstelling acks_late=False wordt het bericht erkend voor uitvoering, waardoor een crash betekent dat de taak verloren gaat. Productiesystemen met kritieke workloads dienen acks_late=True te combineren met idempotent taakontwerp.

Vraag: Leg het verschil uit tussen .delay(), .apply_async() en het direct aanroepen van de taak.

.delay(*args) is syntactische suiker voor .apply_async(args=args). .apply_async() accepteert aanvullende opties zoals countdown, eta, queue, priority en expires. Het direct aanroepen van de taakfunctie (zonder .delay()) voert deze synchroon uit in het huidige proces — bruikbaar voor testen maar in strijd met het doel van asynchrone verwerking.

Vraag: Hoe kan een cachinglaag samenwerken met Celery-taakresultaten?

Taakresultaten die zijn opgeslagen in de Celery result backend kunnen worden gecacht via Django's cache framework. Een view controleert eerst de cache; bij een miss wordt de taak gedispatcht en wordt de AsyncResult-ID opgeslagen. Vervolgverzoeken pollen de result backend via de gecachte ID totdat de taak is voltooid, waarna het eindresultaat wordt gecacht.

Productie-implementatiechecklist

Het deployen van Celery naast Django vereist aandacht voor meerdere operationele aspecten die ook in sollicitatiegesprekken worden bevraagd.

python
# myproject/settings.py — Production configuration
CELERY_TASK_ALWAYS_EAGER = False  # Never True in production
CELERY_TASK_ACKS_LATE = True  # Redelivery on worker crash
CELERY_WORKER_PREFETCH_MULTIPLIER = 1  # Fair scheduling
CELERY_TASK_REJECT_ON_WORKER_LOST = True  # Reject on unexpected exit
CELERY_TASK_TIME_LIMIT = 300  # Hard kill after 5 minutes
CELERY_TASK_SOFT_TIME_LIMIT = 240  # SoftTimeLimitExceeded after 4 min
CELERY_WORKER_MAX_TASKS_PER_CHILD = 1000  # Prevent memory leaks
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True

De instelling WORKER_MAX_TASKS_PER_CHILD herstart workerprocessen na 1000 taken, waardoor geheugenlekken worden voorkomen — een probleem dat Celery 5.6 breder heeft aangepakt met zijn memory leak patches.

Procesbeheer met systemd of supervisor garandeert dat workers herstarten bij een fout. Een minimale systemd-unit:

ini
# /etc/systemd/system/celery-worker.service
[Unit]
Description=Celery Worker
After=network.target redis.service

[Service]
Type=forking
User=django
Group=django
WorkingDirectory=/opt/myproject
ExecStart=/opt/myproject/venv/bin/celery -A myproject worker \
    --loglevel=info --concurrency=4 --pidfile=/var/run/celery/worker.pid
ExecStop=/bin/kill -s TERM $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

Aanvullende productie-aanbevelingen:

  • Broker-redundantie: Redis Sentinel of RabbitMQ-cluster voor failover
  • Gestructureerde logging: JSON-formaat met correlation-ID's voor task-tracing
  • Health checks: Worker-ping via Celery Inspect API in Kubernetes-probes
  • Secrets management: Broker-credentials via omgevingsvariabelen, nooit in de codebase
  • Alerting: Notificaties bij groeiende wachtrijdiepte of hoge foutpercentages

Begin met oefenen!

Test je kennis met onze gespreksimulatoren en technische tests.

Conclusie

  • Celery 5.6.3 (maart 2026) bevat fixes voor geheugenlekken, gestructureerde logging, quorum queue-ondersteuning en psycopg3-compatibiliteit — een upgrade vanuit oudere versies levert onmiddellijk voordeel op.
  • Geef altijd primary keys door aan taken, nooit ORM-objecten. Dit voorkomt serialisatiefouten en verouderde data.
  • Routeer taken naar specifieke wachtrijen op basis van workloadkenmerken. Snelle notificaties en trage rapporten dienen nooit te concurreren om dezelfde workers.
  • Gebruik acks_late=True en idempotent taakontwerp voor kritieke workloads die workercrashes moeten overleven.
  • Stel zowel time_limit als soft_time_limit in op elke taak om te voorkomen dat vastgelopen workers onbeperkt resources verbruiken.
  • Het ingebouwde takenframework van Django 6.0 verwerkt eenvoudige achtergrondjobs; Celery blijft vereist voor gedistribueerde verwerking, scheduling en canvas workflows.
  • Monitor wachtrijdiepte en retry-percentages met Flower of gestructureerde log-aggregatie om capaciteitsproblemen te detecteren voordat ze gebruikers treffen.

Tags

#django
#celery
#async
#python
#interview

Delen

Gerelateerde artikelen