Früher oder später muss jede Python-Webanwendung Arbeit außerhalb des Requests erledigen: die E-Mail nach dem Zurücksenden der Antwort verschicken, den Bericht generieren, den Upload verarbeiten, den wackeligen Drittanbieter-Aufruf wiederholen. Diese Arbeit inline zu erledigen, macht Ihre App langsam und fragil; richtig gemacht brauchen Sie ein Hintergrundjob-System. Die Schwierigkeit liegt in der Auswahl. Celery, RQ, Dramatiq und APScheduler führen alle „Hintergrundaufgaben aus“, lösen aber unterschiedliche Probleme. Dieser Leitfaden vergleicht sie ehrlich, damit Sie gleich das richtige Werkzeug wählen.
So treffen Sie eine sichere Wahl
- Das Grundmodell: ein Broker, eine Warteschlange und Worker-Prozesse
- Celery: der leistungsstarke, funktionsreiche, schwergewichtigere Platzhirsch
- RQ: die einfache, reine Redis-Lösung, die leicht zu durchschauen ist
- Dramatiq: ein moderner Mittelweg mit hervorragenden Standardeinstellungen
- APScheduler: für zeitgesteuerte Aufgaben: ein ganz anderes Problem
Info
Zunächst: zwei unterschiedliche Anforderungen trennen
Aufgabenwarteschlangen (Celery, RQ, Dramatiq) führen Arbeit aus, die von Ihrer App angestoßen wird: „verarbeite das jetzt, außerhalb des Request-Pfads“. Scheduler (APScheduler) führen Arbeit aus, die durch die Zeit angestoßen wird: „mache das jede Nacht um 2 Uhr“. Viele Apps brauchen beides, und die Vermischung ist die Wurzel vieler Verwirrung.
Das gemeinsame mentale Modell
Aufgabenwarteschlangen haben alle dieselbe Grundstruktur. Ihre App stellt einen Job (einen Funktionsnamen plus Argumente) in einen Broker: meist Redis oder RabbitMQ: ein. Separate Worker-Prozesse holen Jobs aus der Warteschlange und führen sie aus, wobei sie Wiederholungen, Fehler und Ergebnisse behandeln. Ihr Webprozess bleibt schnell, weil er nur einstellt; die langsame Arbeit findet woanders statt.
web app ──enqueue──▶ [ BROKER: Redis/RabbitMQ ] ──▶ worker pool ──▶ done
(fast) holds the queue (does the slow work)
Same shape for Celery, RQ, and Dramatiq.
They differ in features, simplicity, and operational weight.
Celery: der funktionsreiche Platzhirsch
Celery ist der langjährige Standard: das leistungsfähigste und am weitesten verbreitete System. Es unterstützt mehrere Broker, komplexe Workflows (Ketten, Gruppen, Akkorde), geplante Aufgaben über seinen Beat-Scheduler, Ratenbegrenzung, Wiederholungen und eine tiefgreifende Konfigurationsoberfläche. Diese Leistungsfähigkeit hat jedoch ihren Preis: Celery ist bekannt für Konfigurationskomplexität und betriebliche Fallstricke, und die Fülle kann für einfache Anforderungen überwältigend sein.
# tasks.py
from celery import Celery
app = Celery("app", broker="redis://localhost:6379/0", backend="redis://localhost:6379/1")
@app.task(bind=True, max_retries=3, autoretry_for=(ConnectionError,), retry_backoff=True)
def send_receipt(self, order_id: int) -> None:
order = Order.objects.get(id=order_id) # pass an ID, not the object
email.send(order.email, render_receipt(order))
# Enqueue from your web app — returns instantly, work happens on a worker.
send_receipt.delay(order_id=42)
# Run workers: celery -A tasks worker --concurrency=8
# Periodic: celery -A tasks beat (Celery's built-in scheduler)
✓ Vorteile
- Die meisten Funktionen und das größte Ökosystem und die größte Community
- Komplexe Workflows: Ketten, Gruppen, Akkorde, Rückrufe
- Mehrere Broker-Backends; ausgereift und im großen Maßstab erprobt
- Eingebaute periodische Planung über Beat
✕ Nachteile
- Konfigurationskomplexität ist real: leicht falsch zu konfigurieren
- Betrieblich aufwändiger als einfachere Alternativen
- Überdimensioniert, wenn Sie nur „diese Funktion später ausführen“ brauchen
- Das Debuggen seiner Grenzfälle hat eine Lernkurve
RQ: einfach aus Prinzip
RQ (Redis Queue) ist das Gegenstück zu Celery: Es ist klein, lesbar und macht genau eines: Python-Funktionen über Redis auf Workern ausführen. Wenn Sie den Quellcode an einem Nachmittag lesen können (was fast möglich ist), können Sie sein Verhalten in der Produktion nachvollziehen. Der Kompromiss sind weniger Funktionen und die Beschränkung auf Redis, aber für einen großen Teil der Anwendungen ist das genau genug.
from redis import Redis
from rq import Queue
# Any plain function is a job — no decorator required.
def send_receipt(order_id: int) -> None:
order = Order.objects.get(id=order_id)
email.send(order.email, render_receipt(order))
queue = Queue(connection=Redis())
queue.enqueue(send_receipt, 42, retry=Retry(max=3)) # enqueue and move on
# Run a worker: rq worker
✓ Vorteile
- Minimal, leicht zu lernen, leicht zu debuggen
- Nur Redis: eine Abhängigkeit, die Sie wahrscheinlich schon betreiben
- Transparentes Verhalten; wenig versteckte Magie
- Passt hervorragend für einfache „mach das später“-Aufgaben
✕ Nachteile
- Weniger fortgeschrittene Funktionen als Celery oder Dramatiq
- Nur Redis: keine RabbitMQ-Option
- Komplexe Workflows erfordern mehr manuelle Zusammenstellung
- Weniger geeignet für sehr hohen Durchsatz und ausgefeilte Pipelines
Dramatiq: der moderne Mittelweg
Dramatiq wurde entwickelt, um den Großteil von Celery's Nützlichkeit zu bewahren, dabei aber einfacher und standardmäßig zuverlässiger zu sein. Es bietet vernünftiges Verhalten ab Werk: automatische Wiederholungen, Nachrichtenaltersgrenzen und Zuverlässigkeitsfunktionen, die Sie anderswo selbst zusammenbauen oder abstimmen müssen. Für Teams, denen Celery zu schwer und RQ zu karg ist, ist Dramatiq oft der ideale Kompromiss.
import dramatiq
# Retries and sane defaults are built in; you opt into specifics per actor.
@dramatiq.actor(max_retries=3, time_limit=30_000)
def send_receipt(order_id: int) -> None:
order = Order.objects.get(id=order_id)
email.send(order.email, render_receipt(order))
send_receipt.send(42) # enqueue
# Run workers: dramatiq tasks
✓ Vorteile
- Saubere API mit zuverlässigen, vernünftigen Standardeinstellungen
- Eingebaute Wiederholungen und Nachrichtenbehandlung gut gelöst
- Unterstützt Redis und RabbitMQ
- Weniger betriebliche Überraschungen als Celery für viele Teams
✕ Nachteile
- Kleinere Community als Celery (aber gesund)
- Weniger exotische Workflow-Primitive als Celery
- Braucht immer noch einen Broker und Worker-Betrieb wie die anderen
- Weniger verbreitet, daher weniger fertige Integrationen
APScheduler: ein anderes Werkzeug für eine andere Aufgabe
APScheduler ist keine Aufgabenwarteschlange: es ist ein Scheduler. Seine Aufgabe ist es, Code basierend auf einem Zeitauslöser auszuführen: jede Stunde, jeden Wochentag um 9 Uhr, in dreißig Minuten. Es ist die prozessinterne Antwort auf „mach das nach Zeitplan“. Wichtig: Es bietet von sich aus keinen verteilten Worker-Pool mit Wiederholungen und Warteschlangen; für geplante Arbeit, die auch schwer ist oder skalieren muss, ist das übliche Muster, dass ein Scheduler lediglich Jobs in eine Aufgabenwarteschlange einstellt.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
scheduler = BackgroundScheduler()
# Don't do the heavy work here — just drop a job onto the real task queue.
@scheduler.scheduled_job(CronTrigger(hour=2, minute=0)) # every day at 02:00
def nightly_reports():
for tenant_id in active_tenant_ids():
generate_report.delay(tenant_id) # Celery/RQ/Dramatiq does the actual work
scheduler.start()
Tipp
Planen, dann einstellen
Das sauberste Muster für schwere wiederkehrende Arbeit ist, einen Scheduler (APScheduler, Celery Beat oder sogar System-Cron) zu verwenden, der nichts weiter tut, als zur richtigen Zeit einen Job in Ihre Aufgabenwarteschlange zu werfen. Der Scheduler entscheidet über das „Wann“; die Warteschlange und ihre Worker kümmern sich um das „Wie“: mit Wiederholungen, Parallelität und Skalierung.
| Dimension | Celery | RQ | Dramatiq | APScheduler |
|---|---|---|---|---|
| Typ | Aufgabenwarteschlange | Aufgabenwarteschlange | Aufgabenwarteschlange | Scheduler |
| Am besten für | Leistung & Ökosystem | Einfachheit | Moderne Balance | Zeitbasierte Auslöser |
| Broker | Redis / RabbitMQ / + | Nur Redis | Redis / RabbitMQ | Prozessintern |
| Komplexität | Hoch | Niedrig | Mittel | Niedrig |
| Wiederholungen integriert | Ja (konfigurierbar) | Einfach | Ja (gute Standardwerte) | Nicht zutreffend |
Der Entscheidungsleitfaden
Brauchen Sie nur ein einfaches „Diese Funktion später ausführen“?
Greifen Sie zu RQ. Wenig bewegliche Teile, Redis haben Sie wahrscheinlich schon, und das Verhalten ist vollständig nachvollziehbar.
Wollen Sie moderne Standardeinstellungen und Zuverlässigkeit ohne die Schwerfälligkeit von Celery?
Wählen Sie Dramatiq. Es trifft die Balance zwischen Funktionsumfang und Einfachheit für die meisten wachsenden Anwendungen.
Brauchen Sie komplexe Workflows, mehrere Broker oder das größte Ökosystem?
Celery bleibt die Antwort: akzeptieren Sie den Konfigurationsaufwand im Austausch für seine Leistungsfähigkeit.
Brauchen Sie zeitgesteuerte Ausführung?
Verwenden Sie APScheduler (oder cron/Celery beat) und lassen Sie ihn für alles Schwergewichtige Aufträge in Ihre Task-Queue einreihen.
Queues führen bedarfsgesteuerte Arbeit aus; Scheduler führen zeitgesteuerte Arbeit aus: wählen Sie je nach Bedarf
Betriebliche Wahrheiten für alle
Was auch immer Sie wählen, die gleichen Realitäten gelten: Machen Sie Tasks idempotent, denn sie werden gelegentlich mehr als einmal ausgeführt; halten Sie Task-Argumente klein und serialisierbar (übergeben Sie eine ID, kein riesiges Objekt); konfigurieren Sie Wiederholungen mit Backoff für vorübergehende Fehler und einen Dead-Letter-Pfad für dauerhafte; und überwachen Sie Ihre Queue-Tiefe, denn ein still wachsender Rückstau ist die Art, wie Hintergrundsysteme unbemerkt versagen.
✓ Vorteile
- Idempotente Tasks, die eine doppelte Ausführung tolerieren
- Kleine, serialisierbare Argumente: IDs übergeben, innerhalb des Tasks neu laden
- Wiederholungen mit Backoff plus ein Dead-Letter-Ziel
- Überwachung von Queue-Tiefe, Fehlerrate und Worker-Zustand
✕ Nachteile
- Keine Übergabe riesiger Objekte oder offener Verbindungen als Task-Argumente
- Keine Annahme einer genau-einmal-Ausführung
- Keine unbegrenzten Wiederholungen, die eine versagende Abhängigkeit bombardieren
- Keine Queue blind gegenüber ihrem Rückstau betreiben
! Häufige Fehler, die es zu vermeiden gilt
-
✕Große Objekte oder offene Verbindungen als Task-Argumente übergeben.
✓Übergeben Sie eine kleine ID und laden Sie innerhalb des Tasks neu; Argumente müssen klein und serialisierbar sein.
-
✕Annehmen, dass ein Task genau einmal ausgeführt wird.
✓Machen Sie Tasks idempotent: sie werden gelegentlich mehr als einmal ausgeführt.
-
✕Unbegrenzte Wiederholungen, die eine versagende Abhängigkeit bombardieren.
✓Wiederholen Sie mit Backoff und leiten Sie dauerhafte Fehler in eine Dead-Letter-Queue.
-
✕Die Queue blind gegenüber ihrem Rückstau betreiben.
✓Überwachen Sie Queue-Tiefe, Fehlerrate und Worker-Zustand: ein stiller Rückstau ist die Art, wie diese Systeme versagen.
? Häufig gestellte Fragen
Was ist der Unterschied zwischen einer Task-Queue und einem Scheduler? +
Eine Task-Queue (Celery, RQ, Dramatiq) führt Arbeit aus, die von Ihrer App außerhalb des Anfragepfads angestoßen wird. Ein Scheduler (APScheduler) führt Arbeit aus, die durch Zeit ausgelöst wird. Viele Apps brauchen beides: und das saubere Muster ist, dass der Scheduler Aufträge in die Queue einreiht.
Celery vs. RQ vs. Dramatiq: welches soll ich wählen? +
RQ für Einfachheit (nur Redis, leicht nachvollziehbar), Dramatiq für moderne Standardeinstellungen und Zuverlässigkeit ohne Celery-Schwerfälligkeit und Celery für komplexe Workflows, mehrere Broker und das größte Ökosystem.
Wann ist Celery übertrieben? +
Wenn Sie nur ein einfaches „Diese Funktion später ausführen“ brauchen. Seine Leistungsfähigkeit geht mit Konfigurationskomplexität und betrieblichen Stolperfallen einher, die ein einfacheres Werkzeug wie RQ vermeidet.
Wie führe ich schwere zeitgesteuerte Arbeit aus? +
Verwenden Sie einen Scheduler (APScheduler, Celery beat oder cron), der nichts weiter tut, als zur richtigen Zeit einen Auftrag in Ihre Task-Queue einzureihen; die Queue und ihre Worker kümmern sich um Wiederholungen, Parallelität und Skalierung.
Warum müssen Tasks idempotent sein? +
Weil eine Zustellung mindestens einmal bedeutet, dass ein Task zweimal laufen kann (ein Worker kann abstürzen, nachdem er die Arbeit erledigt hat, aber bevor er sie bestätigt). Idempotente Tasks machen eine doppelte Ausführung zu einem harmlosen No-Op.
Erfolg
Passen Sie das Werkzeug der Art der Arbeit an
Es gibt keine allgemein beste Option: RQ für Einfachheit, Dramatiq für moderne Ausgewogenheit, Celery für Leistung und Ökosystem, APScheduler für zeitbasierte Auslöser. Stellen Sie fest, ob Ihr Bedarf bedarfsgesteuert oder zeitgesteuert, einfach oder komplex ist, und die richtige Wahl wird offensichtlich. Wenden Sie dann die betrieblichen Grundlagen an, und Ihr Hintergrundsystem wird das zuverlässige, unsichtbare Arbeitstier, das es sein sollte.
Üben unterwegs
Lernen Sie Python, die kostenlose Android-App
Jedes Thema dieser Serie gibt es auch in der App: mundgerechte Lektionen, ausführbare Beispiele, Quizze, Miniprojekte und einen Offline-Python-Spielplatz, der auf Ihrem Handy läuft.
Kommentare
0Noch keine Kommentare. Teile als Erste oder Erster deine Gedanken.