Python Celery Redis : les 8 étapes clés pour passer de zéro à opérationnel

Python Celery Redis : l'essentiel en un article — vrai code, schémas et étapes concrètes, extraits d'un cours de 24 leçons.

Python Celery Redis : les 8 étapes clés pour passer de zéro à opérationnel

Tout le monde peut apprendre Python Celery Redis — à condition de suivre les étapes dans le bon ordre. On a condensé un cours complet de 24 leçons en un parcours clair, avec les extraits de code les plus utiles.

tl;dr
  • Pourquoi Celery
  • Redis essentials
  • Celery setup
  • Tasks et workflows
  • Celery Beat
~$ cat ./parcours.md # Python Celery Redis — 8 chapitres
01
Pourquoi Celery
→ Limites du synchrone→ Architecture Broker / Worker / Backend+ 1 autres leçons
02
Redis essentials
→ Types de donnees Redis→ Pub/Sub et Streams+ 1 autres leçons
03
Celery setup
→ Premier worker et premiere task→ Configuration et best practices+ 1 autres leçons
04
Tasks et workflows
→ Retries et timeouts→ Chain, Group, Chord+ 1 autres leçons
05
Celery Beat
→ Tasks periodiques→ Crontab schedules+ 1 autres leçons
06
Monitoring
→ Flower dashboard→ Logs structures et Sentry+ 1 autres leçons
07
Patterns avancés
→ Rate limiting et quotas→ Idempotence et deduplication+ 1 autres leçons
08
Projet final pipeline ML email
→ Projet - Cahier des charges→ Implementation des tasks+ 1 autres leçons
🏁
Projet final
→ Tu repars avec un projet concret et démontrable

Scheduling dynamique via DB

NOTEObjectif — Permettre aux utilisateurs/admins de modifier les schedules sans redeployer.

Probleme du beat_schedule en code

NOTESi tu veux ajouter/modifier un schedule en prod, il faut redeployer. Pour des tasks user-defined (newsletters, rapports clients), il faut un scheduler dynamique.

django-celery-beat (recommande)

output
pip install django-celery-beat

# settings.py
INSTALLED_APPS = [..., "django_celery_beat"]
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"

# Run migrations
python manage.py migrate

# Beat lit le schedule depuis la DB toutes les 5s
celery -A myproject beat -l info

Tables creees

Creer un schedule via Python

output
from django_celery_beat.models import CrontabSchedule, PeriodicTask

# 1. Definir le timing
schedule, _ = CrontabSchedule.objects.get_or_create(
    minute="30",
    hour="9",
    day_of_week="mon-fri",
    day_of_month="*",
    month_of_year="*",
    timezone="Europe/Paris"
)

# 2. Creer la task periodique
PeriodicTask.objects.create(
    crontab=schedule,
    name="Newsletter Acme Corp",
    task="app.tasks.send_newsletter",
    args=json.dumps(["acme_corp"]),
    kwargs=json.dumps({"template": "weekly"}),
    enabled=True,
    one_off=False,
)

API admin via Django admin

output
# L'admin Django expose deja les modeles
# Tu peux directement aller a /admin/django_celery_beat/periodictask/
# pour ajouter, editer, desactiver via UI

API REST personnalisee

output
@app.post("/schedules")
def create_schedule(data: ScheduleCreate, db: Session = Depends(get_db)):
    schedule = CrontabSchedule.objects.create(
        minute=data.minute, hour=data.hour, ...
    )
    PeriodicTask.objects.create(
        name=data.name,
        crontab=schedule,
        task=data.task_name,
        args=json.dumps(data.args)
    )
    return {"status": "created"}

@app.delete("/schedules/{name}")
def delete_schedule(name: str):
    PeriodicTask.objects.filter(name=name).delete()

Sans Django : celery-redbeat

output
pip install celery-redbeat

# celery_app.py
celery_app.conf.beat_scheduler = "redbeat.RedBeatScheduler"
celery_app.conf.redbeat_redis_url = "redis://redis:6379/2"

# Creer un schedule
from redbeat import RedBeatSchedulerEntry
from celery.schedules import crontab

entry = RedBeatSchedulerEntry(
    name="my-task",
    task="app.tasks.my_task",
    schedule=crontab(hour=9, minute=0),
    app=celery_app,
    args=["arg1"]
)
entry.save()

# Supprimer
entry.delete()

Cas d'usage : newsletters multi-tenant

output
# Modele DB
class Newsletter(models.Model):
    name = models.CharField(max_length=200)
    schedule_cron = models.CharField(max_length=100)        # "0 9 * * mon"
    enabled = models.BooleanField(default=True)
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        self.sync_celery_beat()
    
    def sync_celery_beat(self):
        m, h, dom, mon, dow = self.schedule_cron.split()
        schedule, _ = CrontabSchedule.objects.get_or_create(
            minute=m, hour=h, day_of_month=dom,
            month_of_year=mon, day_of_week=dow
        )
        PeriodicTask.objects.update_or_create(
            name=f"newsletter_{self.id}",
            defaults={
                "crontab": schedule,
                "task": "app.tasks.send_newsletter",
                "args": json.dumps([self.id]),
                "enabled": self.enabled
            }
        )

Projet - Cahier des charges

NOTEMission — Construire un systeme de recommandation produits envoye par email aux clients chaque semaine.

Specifications

NOTEFonctionnel :
  • Pour chaque user actif : recuperer historique d'achat
  • Generer 5 recommandations via ML (cosine similarity ou modele plus avance)
  • Composer un email HTML personnalise
  • Envoyer via SendGrid avec retry
  • Tracker delivery, open, click
  • Frequence : hebdomadaire, lundi 9h
Non fonctionnel :
  • Scale : 100k+ users
  • Idempotence : pas de double envoi
  • Rate limit SendGrid : 100 emails/seconde
  • Reprise sur erreur sans tout rejouer

Architecture cible

output
+---------------+
| Celery Beat   |  cron mon 9h
| (1 instance)  |
+-------+-------+
        |
        v
+---------------+      +-----------+
| dispatch_     |--->  | Redis     |
| weekly_emails |      | broker    |
| (1 task)      |      +-----+-----+
+---------------+            |
                             v
                +------------+------------+
                |                         |
        +-------v------+         +--------v-------+
        | Worker emails|         | Worker ML      |
        | (10 procs)   |         | (2 procs, GPU) |
        +-------+------+         +--------+-------+
                |                         |
                v                         v
        +-------+------+         +--------+-------+
        | SendGrid     |         | Modele Recommandation|
        | (rate limit) |         | + DB historique|
        +--------------+         +----------------+
                |
                v
        +-------+------+
        | Webhook      |
        | open/click   |
        +--------------+

Structure du projet

output
recommender/
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── app/
│   ├── celery_app.py
│   ├── config.py
│   ├── tasks/
│   │   ├── orchestrator.py      # dispatch_weekly_emails
│   │   ├── ml.py                # compute_recommendations
│   │   ├── email.py             # render + send
│   │   └── tracking.py          # webhooks
│   ├── models/                  # SQLAlchemy
│   ├── ml/
│   │   └── recommender.py
│   └── templates/
│       └── weekly.html
└── tests/

Modeles DB

output
class User(Base):
    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str]
    active: Mapped[bool] = mapped_column(default=True)
    last_recos_sent: Mapped[datetime | None]

class Product(Base):
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    category: Mapped[str]
    embedding: Mapped[list[float]]    # vector pour ML

class Order(Base):
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
    product_id: Mapped[int] = mapped_column(ForeignKey("products.id"))
    created_at: Mapped[datetime]

class EmailJob(Base):
    """Track envois pour idempotence"""
    id: Mapped[int] = mapped_column(primary_key=True)
    user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
    week_key: Mapped[str]                  # "2026-W21"
    status: Mapped[str]                     # pending|sent|failed|opened|clicked
    sendgrid_msg_id: Mapped[str | None]
    created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
    
    __table_args__ = (UniqueConstraint("user_id", "week_key"),)

Configuration multi-queue

output
celery_app.conf.task_queues = (
    Queue("orchestrator"),
    Queue("ml"),
    Queue("emails"),
    Queue("tracking"),
)

celery_app.conf.task_routes = {
    "app.tasks.orchestrator.*": {"queue": "orchestrator"},
    "app.tasks.ml.*": {"queue": "ml"},
    "app.tasks.email.*": {"queue": "emails"},
    "app.tasks.tracking.*": {"queue": "tracking"},
}

celery_app.conf.beat_schedule = {
    "weekly-recos": {
        "task": "app.tasks.orchestrator.dispatch_weekly_emails",
        "schedule": crontab(hour=9, minute=0, day_of_week="mon")
    }
}

SLOs cibles

NOTE
  • Tous les emails envoyes en < 2h pour 100k users
  • Taux d'echec final < 0.5%
  • Latence webhook tracking < 1s
  • Resilience : si SendGrid down 10min, reprise automatique

Resume

NOTEA retenir
  • Separer ML (lourd), emails (debit), orchestrator (controle)
  • EmailJob avec UniqueConstraint = idempotence
  • Beat pour declenchement hebdo
  • Tracking via webhook SendGrid

Persistance et eviction

NOTEObjectif — Configurer la persistance et l'eviction memoire en production.

RDB : snapshots

output
# redis.conf
save 900 1          # snapshot si >=1 modif en 15min
save 300 10         # snapshot si >=10 modifs en 5min
save 60 10000       # snapshot si >=10000 modifs en 1min

dbfilename dump.rdb
dir /var/lib/redis
NOTERDB : snapshot binaire compact, restore rapide. Mais peut perdre quelques minutes en cas de crash.

AOF : append-only log

output
# redis.conf
appendonly yes
appendfilename "appendonly.aof"

appendfsync always       # lent mais 0 perte
appendfsync everysec     # defaut : 0-1s de perte
appendfsync no           # OS decide

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
NOTEAOF : chaque ecriture logged. Plus de garanties, mais plus gros sur disque.

Hybride : RDB + AOF

output
# Recommande en prod : les deux actives
save 900 1
appendonly yes
appendfsync everysec

# Au restart : Redis charge AOF (plus a jour)

maxmemory et eviction

output
# Limite memoire
maxmemory 2gb

# Politique quand plein
maxmemory-policy allkeys-lru        # supprime les moins recemment utilises (cache)

Politiques d'eviction

PolitiqueComportement
noevictionRejette les ecritures (defaut)
allkeys-lruSupprime LRU sur toutes les cles
volatile-lruLRU sur cles avec TTL
allkeys-lfuMoins frequemment utilisees
allkeys-randomAleatoire
volatile-ttlCle avec TTL la plus courte d'abord

Backups

output
# Snapshot manuel
redis-cli BGSAVE              # asynchrone
redis-cli SAVE                # synchrone (bloquant !)

# Copier le dump
cp /var/lib/redis/dump.rdb /backup/dump-$(date +%F).rdb

# Restore
systemctl stop redis
cp /backup/dump-2026-05-27.rdb /var/lib/redis/dump.rdb
systemctl start redis

Replication master-replica

output
# Sur le replica
replicaof master.redis.local 6379

# Verifier
redis-cli INFO replication
# role:slave
# master_link_status:up

# Failover automatique : Redis Sentinel
# Sharding : Redis Cluster
va-plus-loin

Cet article couvre les extraits les plus utiles — le cours complet Python Celery Redis (8 chapitres, 24 leçons, exercices corrigés et projet final) t'emmène jusqu'au bout.

./acceder-au-cours-complet cours gratuit : Vibe Coding

FAQ

Combien de temps pour apprendre Python Celery Redis ?
Avec une progression structurée (8 chapitres, 24 leçons courtes et pratiques), on atteint un niveau opérationnel en quelques semaines à raison de 30 à 60 minutes par jour. L'important est de pratiquer chaque notion immédiatement.
Faut-il des prérequis ?
Des bases en informatique suffisent. Si tu sais utiliser un terminal et lire du code simple, tu es prêt.
Par où commencer concrètement ?
Reproduis les commandes de cet article, puis suis le cours complet Python Celery Redis : il enchaîne les 24 leçons dans l'ordre, avec exercices et projet final.

📬 Tu veux recevoir ce type de guide chaque semaine ? Abonne-toi gratuitement — code réel, zéro blabla.