Communitygithub.com

django-celery

Modèles de tâches asynchrones Django + Celery — configuration, conception de tâches, planification Beat, tentatives, workflows Canvas, surveillance et tests. À utiliser lors de l'ajout de travaux en arrière-plan, de tâches planifiées ou de traitement asynchrone à une application Django.

Qu'est-ce que django-celery ?

Ce skill fournit des modèles de qualité production pour le traitement de tâches en arrière-plan dans Django avec Celery, utilisant Redis ou RabbitMQ comme courtier. Il couvre la configuration complète du projet : installation, point d'entrée Celery, paramètres Django (courtier, sérialisation, comportement des tâches, limites de temps) et exécution des workers. Il détaille les patrons de conception essentiels : tâches de base, tâches avec tentatives automatiques (exponentielle, gigue), tâches idempotentes avec gardes, et gestion des limites de temps. L'appel de tâches asynchrone, différé ou via files d'attente est expliqué, tout comme la planification périodique (dB ou code) avec Celery Beat. Les workflows Canvas (chaînes, groupes, accords) sont présentés pour la composition de tâches. La gestion des erreurs inclut l'envoi à Sentry et la file d'attente de lettres mortes. Les tests unitaires et d'intégration sont traités (mode eager, tests de tentatives). Enfin, des anti-patrons et une checklist de production sont fournis pour éviter les pièges courants. Le skill est compatible avec les projets Django utilisant Celery, et s'intègre avec les skills `django-patterns`, `django-tdd`, et `python-testing`.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/django-celery

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles de Tâches Asynchrones Django + Celery

Modèles de qualité production pour le traitement de tâches en arrière-plan dans Django avec Celery, utilisant Redis ou RabbitMQ.

Quand Activer

  • Ajout de travaux en arrière-plan ou de traitement asynchrone à une application Django
  • Mise en œuvre de tâches périodiques/planifiées
  • Délestage d'opérations lentes (email, génération PDF, appels API) du cycle de requête
  • Configuration de Celery Beat pour une planification de type cron
  • Débogage d'échecs de tâches, de tentatives ou de files d'attente en backlog
  • Écriture de tests pour les tâches Celery

Configuration du Projet

Installation

pip install 'celery[redis]' django-celery-results django-celery-beat

celery.py — Point d'Entrée de l'Application

# config/celery.py
import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development')

app = Celery('monprojet')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()  # Découvre tasks.py dans chaque INSTALLED_APP

@app.task(bind=True, ignore_result=True)
def debug_task(self):
    print(f'Requête : {self.request!r}')
# config/__init__.py
from .celery import app as celery_app

__all__ = ('celery_app',)

Paramètres Django

# config/settings/base.py

# Courtier (Redis recommandé pour la production)
CELERY_BROKER_URL = env('CELERY_BROKER_URL', default='redis://localhost:6379/0')
CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND', default='django-db')

# Sérialisation
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

# Comportement des tâches
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60        # Limite dure : 30 min
CELERY_TASK_SOFT_TIME_LIMIT = 25 * 60   # Limite douce : envoie SoftTimeLimitExceeded
CELERY_WORKER_PREFETCH_MULTIPLIER = 1   # Empêche l'accaparement des longues tâches
CELERY_TASK_ACKS_LATE = True            # Remet en file d'attente si le worker plante

# Persistance des résultats
CELERY_RESULT_EXPIRES = 60 * 60 * 24   # Conserver les résultats 24 heures

# Planificateur Beat (pour les tâches périodiques)
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

# Applications installées
INSTALLED_APPS += [
    'django_celery_results',
    'django_celery_beat',
]

Exécution des Workers

# Démarrer le worker (développement)
celery -A config worker --loglevel=info

# Démarrer le planificateur Beat (tâches périodiques)
celery -A config beat --loglevel=info --scheduler django_celery_beat.schedulers:DatabaseScheduler

# Worker + Beat combinés (développement uniquement, jamais en production)
celery -A config worker --beat --loglevel=info

# Production : plusieurs workers avec concurrence
celery -A config worker --loglevel=warning --concurrency=4 -Q default,high_priority

Modèles de Conception de Tâches

Tâche Basique

# apps/notifications/tasks.py
from celery import shared_task
import logging

logger = logging.getLogger(__name__)

@shared_task(name='notifications.send_welcome_email')
def send_welcome_email(user_id: int) -> None:
    """Envoyer un email de bienvenue à un utilisateur nouvellement inscrit."""
    from apps.users.models import User
    from apps.notifications.services import EmailService

    try:
        user = User.objects.get(pk=user_id)
    except User.DoesNotExist:
        logger.warning('send_welcome_email : utilisateur %s introuvable', user_id)
        return  # Idempotent — ne pas lever, tâche déjà impossible à accomplir

    EmailService.send_welcome(user)
    logger.info('Email de bienvenue envoyé à l\'utilisateur %s', user_id)

Tâche avec Tentatives

@shared_task(
    bind=True,
    name='integrations.sync_to_crm',
    max_retries=5,
    default_retry_delay=60,       # secondes avant la première tentative
    autoretry_for=(ConnectionError, TimeoutError),
    retry_backoff=True,           # backoff exponentiel
    retry_backoff_max=600,        # plafonné à 10 minutes
    retry_jitter=True,            # randomisation pour éviter l'effet de troupeau
)
def sync_contact_to_crm(self, contact_id: int) -> dict:
    """Synchroniser un contact vers un CRM externe avec tentatives en cas d'échecs transitoires."""
    from apps.crm.services import CRMClient

    try:
        result = CRMClient().sync(contact_id)
        return result
    except CRMClient.RateLimitError as exc:
        # Délai de tentative spécifique depuis l'en-tête de réponse
        raise self.retry(exc=exc, countdown=int(exc.retry_after))

Modèle de Tâche Idempotente

Concevez les tâches pour qu'elles puissent être exécutées plusieurs fois en toute sécurité avec les mêmes entrées :

@shared_task(name='orders.mark_shipped')
def mark_order_shipped(order_id: int, tracking_number: str) -> None:
    """Marquer la commande comme expédiée — peut être exécutée plusieurs fois en toute sécurité."""
    from apps.orders.models import Order

    updated = Order.objects.filter(
        pk=order_id,
        status=Order.Status.PROCESSING,    # Garde : ne mettre à jour que si pas déjà expédiée
    ).update(
        status=Order.Status.SHIPPED,
        tracking_number=tracking_number,
    )

    if not updated:
        logger.info('mark_order_shipped : commande %s déjà expédiée ou introuvable', order_id)

Tâche avec Limite de Temps Douce

from celery.exceptions import SoftTimeLimitExceeded

@shared_task(
    bind=True,
    name='reports.generate_pdf',
    soft_time_limit=120,
    time_limit=150,
)
def generate_pdf_report(self, report_id: int) -> str:
    """Générer un rapport PDF avec gestion gracieuse du délai d'attente."""
    from apps.reports.services import PDFGenerator

    try:
        path = PDFGenerator.build(report_id)
        return path
    except SoftTimeLimitExceeded:
        # Nettoyer les fichiers partiels avant l'arrêt forcé
        PDFGenerator.cleanup(report_id)
        raise

Appeler des Tâches

from datetime import timedelta
from django.utils import timezone

# Lancer et oublier (asynchrone)
send_welcome_email.delay(user.pk)

# Planifier dans le futur
send_reminder.apply_async(args=[user.pk], countdown=3600)  # 1 heure
send_reminder.apply_async(args=[user.pk], eta=timezone.now() + timedelta(days=1))

# Appliquer avec routage de file d'attente
sync_contact_to_crm.apply_async(args=[contact.pk], queue='high_priority')

# Exécuter de manière synchrone (tests / débogage uniquement)
result = generate_pdf_report.apply(args=[report.pk])

Planification Beat (Tâches Périodiques)

Planification Définie dans le Code

# config/settings/base.py
from celery.schedules import crontab

CELERY_BEAT_SCHEDULE = {
    'nettoyer-sessions-expirees': {
        'task': 'users.cleanup_expired_sessions',
        'schedule': crontab(hour=2, minute=0),   # 2h du matin chaque jour
    },
    'synchroniser-inventaire': {
        'task': 'products.sync_inventory',
        'schedule': 60.0,                         # toutes les 60 secondes
    },
    'resume-hebdomadaire': {
        'task': 'notifications.send_weekly_digest',
        'schedule': crontab(day_of_week='monday', hour=8, minute=0),
    },
}

Planification Définie dans la Base de Données (via django-celery-beat)

# Gérer les tâches périodiques depuis l'admin Django ou le code
from django_celery_beat.models import PeriodicTask, CrontabSchedule
import json

schedule, _ = CrontabSchedule.objects.get_or_create(
    hour='*/6', minute='0',
    timezone='UTC',
)

PeriodicTask.objects.update_or_create(
    name='Synchroniser l\'inventaire toutes les 6 heures',
    defaults={
        'crontab': schedule,
        'task': 'products.sync_inventory',
        'args': json.dumps([]),
        'enabled': True,
    }
)

Canvas : Chaînage et Regroupement de Tâches

from celery import chain, group, chord

# Chaîne : exécuter les tâches séquentiellement, en passant les résultats
pipeline = chain(
    fetch_data.s(source_id),
    transform_data.s(),          # reçoit le résultat de fetch_data comme premier argument
    load_to_warehouse.s(),
)
pipeline.delay()

# Groupe : exécuter les tâches en parallèle
parallel = group(
    send_welcome_email.s(user_id)
    for user_id in new_user_ids
)
parallel.delay()

# Accord : tâches parallèles + rappel quand tout est terminé
result = chord(
    group(process_chunk.s(chunk) for chunk in data_chunks),
    aggregate_results.s(),       # appelé avec la liste des résultats des morceaux
)
result.delay()

Gestion des Erreurs et File d'Attente de Lettres Mortes

# apps/core/tasks.py
from celery.signals import task_failure

@task_failure.connect
def on_task_failure(sender, task_id, exception, args, kwargs, traceback, einfo, **kw):
    """Journaliser tous les échecs de tâches vers Sentry / alertes."""
    import sentry_sdk
    with sentry_sdk.new_scope() as scope:
        scope.set_context('celery', {
            'task': sender.name,
            'task_id': task_id,
            'args': args,
            'kwargs': kwargs,
        })
        sentry_sdk.capture_exception(exception)
# Router les tâches échouées vers la file d'attente de lettres mortes après le nombre max de tentatives
@shared_task(
    bind=True,
    max_retries=3,
    name='payments.charge_card',
)
def charge_card(self, order_id: int) -> None:
    from apps.payments.models import Order, FailedCharge

    try:
        _do_charge(order_id)
    except Exception as exc:
        if self.request.retries >= self.max_retries:
            # Persister dans la table de lettres mortes pour révision manuelle
            FailedCharge.objects.create(
                order_id=order_id,
                error=str(exc),
                task_id=self.request.id,
            )
            return  # Ne pas lever — la tâche a définitivement échoué
        raise self.retry(exc=exc)

Tester les Tâches Celery

Tests Unitaires (Sans Courtier)

# tests/test_tasks.py
import pytest
from unittest.mock import patch, MagicMock
from apps.notifications.tasks import send_welcome_email

class TestSendWelcomeEmail:

    @pytest.mark.django_db
    def test_envoie_email_a_utilisateur_existant(self, user):
        with patch('apps.notifications.services.EmailService') as mock_email:
            send_welcome_email(user.pk)
            mock_email.send_welcome.assert_called_once_with(user)

    @pytest.mark.django_db
    def test_ignore_gracieusement_utilisateur_manquant(self):
        """Ne doit pas lever si l'utilisateur est supprimé entre la mise en file et l'exécution."""
        send_welcome_email(99999)  # Utilisateur inexistant — ne doit pas lever

Tests d'Intégration avec CELERY_TASK_ALWAYS_EAGER

# config/settings/test.py
CELERY_TASK_ALWAYS_EAGER = True      # Exécuter les tâches de manière synchrone dans les tests
CELERY_TASK_EAGER_PROPAGATES = True  # Propager les exceptions des tâches

# tests/test_integration.py
@pytest.mark.django_db
def test_inscription_declenche_email_bienvenue(client):
    with patch('apps.notifications.services.EmailService') as mock_email:
        response = client.post('/api/users/', {
            'email': '[email protected]',
            'password': 'motdepassefort123',
        })

    assert response.status_code == 201
    mock_email.send_welcome.assert_called_once()

Test des Tentatives

@pytest.mark.django_db
def test_tache_retente_sur_erreur_connexion():
    with patch('apps.crm.services.CRMClient.sync') as mock_sync:
        mock_sync.side_effect = ConnectionError('timeout')

        with pytest.raises(ConnectionError):
            sync_contact_to_crm.apply(args=[1], throw=True)

        assert mock_sync.call_count == 1  # Première tentative uniquement en eager

Surveillance

# Inspecter les workers et files d'attente actifs
celery -A config inspect active
celery -A config inspect stats
celery -A config inspect reserved

# Vérifier les longueurs de file (Redis)
redis-cli llen celery

# Flower : moniteur en temps réel basé sur le web
pip install flower
celery -A config flower --port=5555

Anti-Patrons

# MAUVAIS : Passer des instances de modèles — elles peuvent être obsolètes au moment de l'exécution
send_welcome_email.delay(user)        # Ne jamais passer d'objets ORM
send_welcome_email.delay(user.pk)     # Toujours passer les PK

# MAUVAIS : Appeler des tâches de manière synchrone dans les vues de production
result = generate_report.apply()      # Bloque le thread de la requête

# MAUVAIS : Tâche non idempotente sans gardes
@shared_task
def charger_et_executer(commande_id):
    commande.charge()     # Peut facturer deux fois si la tâche retente !
    commande.executer()

# BON : Idempotent avec garde de statut
@shared_task
def charger_et_executer(commande_id):
    commande = Commande.objects.select_for_update().get(pk=commande_id)
    if commande.statut != Commande.Statut.EN_ATTENTE:
        return  # Déjà traité
    commande.charge()
    commande.executer()

Checklist de Production

VérificationRéglage
Redémarrage du worker en cas de crashUnité supervisord ou systemd
CELERY_TASK_ACKS_LATE = TrueRemettre les tâches en file d'attente si le worker plante
CELERY_WORKER_PREFETCH_MULTIPLIER = 1Distribution équitable des longues tâches
Files d'attente séparées par priorité-Q default,high_priority,low_priority
CELERY_TASK_SOFT_TIME_LIMIT définiDélai d'attente gracieux avant arrêt forcé
Intégration SentryCapturer tous les signaux task_failure
Flower ou autre moniteurVisibilité sur les profondeurs de file
Beat exécuté sur un seul nœudEmpêche l'exécution en double des tâches planifiées

Compétences Associées

  • django-patterns — ORM, couche service et structure de projet
  • django-tdd — Tester les modèles, vues et services Django
  • python-testing — Configuration de pytest et fixtures

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Skills associés