Heute werde ich also über eine Celery-Alternative namens Huey sprechen, die viel einfacher einzurichten ist als Celery und im Vergleich dazu viel kleiner ist.
Der Grund, warum ich mich entschieden habe, Huey auszuprobieren, liegt darin, dass ich bei der Ausführung einiger gängiger Aufgaben manchmal Probleme mit Celery hatte, da die Dokumentation nicht besonders gut ist.
Für diejenigen, die Celery nicht kennen oder es noch nie verwendet haben: Huey ist eine asynchrone Aufgabenwarteschlange, mit der Sie geplante Aufgaben oder Aufgaben mit langer Laufzeit im Hintergrund ausführen können.
Wir werden die folgenden Pakete installieren:
Dem folgenden Blog liegt ein GitHub-Repo bei, mit dem Sie das von uns erstellte Demoprojekt testen können.
Klicken Sie hier, um das Repo anzuzeigen.
Öffnen Sie das Terminal und geben Sie Folgendes ein, um ein Verzeichnis zu erstellen. Sie können diesen Schritt überspringen und ihn direkt im Datei-Explorer ausführen.
mkdir huey_demo
Lassen Sie uns zunächst eine virtuelle Umgebung erstellen, um unsere Projektabhängigkeiten zu installieren:
python -m venv venv
Aktivieren Sie die virtuelle Umgebung (Linux):
source venv/bin/activate
Geben Sie den folgenden Befehl in das Terminal ein, um alle Abhängigkeiten zu installieren:
pip install Django==4.0.4 redis==4.2.2 huey==2.4.3
Als ich diesen Artikel verfasste, waren dies die Versionen, mit denen ich dieses Setup getestet habe. Behalten Sie das Github Repo im Auge, um in Zukunft auf die neueste Version aktualisiert zu werden.
Erstellen Sie das Django-Projekt, indem Sie den folgenden Befehl in das Terminal eingeben:
django-admin startproject django_huey_demo
Wechseln Sie in das Django-Projektverzeichnis:
cd django_huey_demo
Erstellen Sie die App im Rahmen unseres Projekts:
python manage.py startapp demo
Fügen Sie die erstellte App in das Projekt settings.py
ein und nehmen Sie die folgenden Änderungen vor:
INSTALLED_APPS = [ # Existing Apps "demo.apps.DemoConfig", # <== Add this line ]
Setzen Sie den Debug-Modus in settings.py
auf False
:
DEBUG=False
Wir setzen Debug auf False, damit wir sehen können, wie Huey in der Produktion läuft, mehr dazu später.
Nachdem wir nun mit der Einrichtung unseres Projekts fertig sind, ist es ein guter Zeitpunkt, Ihnen zu zeigen, was wir heute bauen werden.
Wir holen uns täglich das „Wort des Tages“ von der Wordnik-API . Anschließend speichern wir das Wort, seine Definition und ein Beispiel des Wortes in einem Satz in unserer Datenbank.
Wir werden mit Huey eine regelmäßige Aufgabe einrichten, die das Wort des Tages abruft und speichert.
Zum Speichern des Wortes erstellen wir ein Django-Modell davon.
Sie können dieser Anleitung folgen, um den API-Schlüssel zu erhalten.
Wir müssen Huey zu den installierten Apps unseres Projekts hinzufügen. Nehmen Sie daher die folgenden Änderungen in der Datei settings.py
vor:
INSTALLED_APPS = [ # Existing apps 'huey.contrib.djhuey', # <== Add this line ]
Wir müssen Redis für Huey installieren, um darin Informationen über in die Warteschlange gestellte Aufgaben zu speichern, wie wir es auch mit Celery gemacht haben. Unter dem folgenden Link können Sie Redis basierend auf Ihrem spezifischen Betriebssystem installieren.
Wenn Sie mit der Verwendung von Docker vertraut sind, können Sie den folgenden Befehl verwenden:
docker run --name redis_huey -p 6379:6379 -d redis
Standardmäßig versucht Huey, eine Verbindung zum Redis-Server herzustellen, der auf localhost:6379
läuft. Wenn dieser nicht vorhanden ist, wird ein Fehler ausgegeben.
Fügen Sie Ihrer Datei demo/models.py
den folgenden Code hinzu:
from django.db import models class Word(models.Model): word = models.CharField(max_length=200) part_of_speech = models.CharField(max_length=100) definition = models.TextField() example = models.TextField() def __str__(self): return self.word
Migrationen durchführen:
python manage.py makemigrations demo
Migrationen anwenden:
python manage.py migrate demo
Erstellen Sie eine Datei mit dem Namen „ tasks.py
im Verzeichnis der Demo-App. Wir haben unsere Datei „ tasks.py
genannt, damit Huey die in unseren registrierten Apps vorhandenen Aufgaben automatisch erkennen kann. Wenn wir unsere Datei anders nennen würden, müssten wir unsere Aufgabe manuell registrieren. Wenn Sie mehr wissen möchten, können Sie sich hier die Huey-Dokumentation ansehen.
Bevor wir die Aufgabendefinition schreiben, müssen wir eine zusätzliche requests
installieren. Installieren Sie diese, indem Sie Folgendes in Ihr Terminal eingeben:
pip install requests==2.27.1
Jetzt kommt der Code:
import requests from django.conf import settings from huey import crontab from huey.contrib.djhuey import db_periodic_task from demo.models import Word @db_periodic_task(crontab(hour="18", minute="00")) def fetch_daily_word(): r = requests.get( f"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key={settings.WORDNIK_API_KEY}") data = r.json() Word.objects.get_or_create( word=data["word"], part_of_speech=data["definitions"][0]["partOfSpeech"], definition=data["definitions"][0]["text"], example=data["examples"][0]["text"] )
Fügen Sie in Ihren Projekteinstellungen die folgende Zeile hinzu:
WORDNIK_API_KEY = "api-key-here"
Dieser Codeblock ist möglicherweise recht umfangreich, daher gehen wir ihn Stück für Stück durch:
Huey Dekorateur
from huey.contrib.djhuey import db_periodic_task
Dies ist ein von Huey bereitgestellter Dekorator zum Registrieren periodischer Aufgaben, bei denen mit der Datenbank gearbeitet wird. Dieser Dekorator schließt die Datenbankverbindung nach Abschluss der Aufgabe automatisch. Weitere Einzelheiten finden Sie hier.
Crontab-Zeitplan
@db_periodic_task(crontab(hour="18", minute="00"))
Wir übergeben das Argument crontab(hour="18", minute="00")
an unseren periodischen Task-Dekorator. Dies weist Huey an, unseren Task jeden Tag um 18 Uhr auszuführen. Sie können diese Website nutzen, um Ihre Crontab-Zeitpläne zu erstellen, ich verwende sie jedes Mal.
Wordnik API-Schlüssel
from django.conf import settings # Usage ## settings.WORDNIK_API_KEY
from django.conf import settings
ist die Standardmethode zum Importieren von Daten aus unseren Projekteinstellungen. Dies ist nützlich, wenn wir mehrere Einstellungsdateien für verschiedene Umgebungen eingerichtet haben, sodass es weiß, aus welcher Datei es auswählen muss, ohne dass wir uns darum kümmern müssen. Es findet aus der Umgebungsvariable DJANGO_SETTINGS_MODULE
heraus, welche Einstellungsdatei wir verwenden. Aber Sie müssen sich um diese Details keine Gedanken machen.
Dann verwenden wir den Schlüssel in unserem Wordnik-API-Aufruf.
Wordnik API-Aufruf
r = requests.get( f"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key={settings.WORDNIK_API_KEY}")
Hier verwenden wir das Anforderungsmodul, um eine GET-Anforderung an die Wordnik-API zu senden und dabei unseren API-Schlüssel zur Authentifizierung zu übergeben.
Wörter in der Datenbank speichern
data = r.json() Word.objects.get_or_create( word=data["word"], part_of_speech=data["definitions"][0]["partOfSpeech"], definition=data["definitions"][0]["text"], example=data["examples"][0]["text"] )
Nachdem wir die API-Antwort analysiert haben, speichern wir die Wortdefinition in unserer Datenbank. Wir verwenden hier die Methode get_or_create
anstelle der Methode create
, damit wir nicht mehrere Kopien desselben Wortes in unserer Datenbank erstellen, wenn dieses Wort jemals von der Wordnik-API wiederholt wird.
Wordnik API-Antwort
So sieht die Wordnik-API-Antwort für den Endpunkt „Wort des Tages“ aus. Einige der irrelevanten Abschnitte der Antwort wurden der Kürze halber gekürzt.
{ "word": "stolon", "definitions": [ { "source": "ahd-5", "text": "A long thin stem that usually grows horizontally along the ground and produces roots and shoots at widely spaced nodes, as in a strawberry plant.", "note": null, "partOfSpeech": "noun" }, // More definitions here... ], "publishDate": "2022-05-08T03:00:00.000Z", "examples": [ { "title": "4.1 Nursery establishment", "text": "A stolon is a stem that grows along the ground, producing at its nodes new plants with roots and upright stems.", // Additional data here... }, // More examples here... ], // Additional fields here... }
Sie können den Huey-Worker starten, indem Sie den folgenden Befehl in Ihr Terminal eingeben:
python manage.py run_huey
Sie können dem obigen Befehl mehrere Flags übergeben, die ändern, was in der Konsole protokolliert wird, beispielsweise:
-v, --verbose
– ausführliche Protokollierung (einschließlich DEBUG-Ebene)-q, --quiet
– minimale Protokollierung-S, --simple
– einfaches Protokollierungsformat („Zeitnachricht“)
Um sich verschiedene andere Optionen zur Protokollierung anzusehen, sehen Sie sich die Dokumentation hier an.
Huey verfügt über mehrere Task-Dekoratoren, abhängig von den Vorgängen, die Sie innerhalb der Aufgabe ausführen.
Im Folgenden erkläre ich kurz, was sie alle bewirken.
Hier ist die Importanweisung für alle Dekoratoren:
from huey.contrib.djhuey import task, periodic_task, db_task, db_periodic_task
task
: Eine reguläre Aufgabe.periodic_task
: Wenn Sie eine Aufgabe regelmäßig basierend auf einem Zeitplan ausführen möchten.db_task
: Wenn Sie DB-Operationen innerhalb Ihrer Aufgabe durchführen möchten.db_periodic_task
: Wenn Sie DB-Operationen in einer periodischen Aufgabe ausführen möchten.Lassen Sie mich Ihnen einige weitere Beispiele zeigen, wie Sie crontab zum Planen Ihrer Aufgaben verwenden können.
crontab(minute='*/3')
würde die Aufgabe so planen, dass sie alle drei Minuten ausgeführt wird.crontab(hour='*/3', minute='5')
würde eine Aufgabe erstellen, die jede dritte Stunde 5 Minuten nach Beginn der Sitzung ausgeführt wird.crontab(minute='00', hour='10', month='*/2', day_of_week='*/5')
würde eine Aufgabe erstellen, die an jedem 5. Tag der Woche und jeden 2. Monat um 10:00 Uhr ausgeführt wird. Beispielsweise haben Sie die folgende Aufgabe in tasks.py
definiert:
from huey.contrib.djhuey import task @task() def count(): for i in range(10): print(i)
Wenn Sie diese Aufgabe nun aufrufen möchten, sie aber erst nach 5 Sekunden ausführen möchten, können Sie Folgendes tun:
count.schedule(delay=5)
Der delay
nimmt Werte in Sekunden an. Wenn Sie also eine Ausführung nach 5 Minuten wünschen, geben Sie 300 Sekunden an.
Angenommen, Sie fügen unserer bestehenden Aufgabe die folgende Logik hinzu:
@db_periodic_task(crontab(hour="18", minute="00"), retries=2) def fetch_daily_word(): r = requests.get( f"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key={settings.WORDNIK_API_KEY}") if r.status_code != 200: raise Exception("Unable to fetch data from Wordnik API") ## Add this logic else: data = r.json() Word.objects.get_or_create( word=data["word"], part_of_speech=data["definitions"][0]["partOfSpeech"], definition=data["definitions"][0]["text"], example=data["examples"][0]["text"] )
Wir haben also die Logik hinzugefügt, um den Statuscode der Antwort zu prüfen. Wenn dieser etwas anderes als 200 ist, wird die Aufgabe bis zu zweimal wiederholt. Diese Wiederholungsversuche würden jedoch ohne Zeitlücke zwischen den beiden Versuchen erfolgen. Was ist nun, wenn Sie mehrere Versuche dieser Aufgabe verzögern möchten? Wir können dies tun, indem wir das Argument retry_delay
übergeben. Es akzeptiert Werte in Sekunden.
@db_periodic_task(crontab(hour="18", minute="00"), retries=2, retry_delay=10)
Dies führt zu einer Verzögerung von 10 Sekunden zwischen mehreren Versuchen.
Huey verfügt über eine Standardeinstellung, die die Arbeit mit Huey während der Entwicklung in Django erleichtert. Wenn also DEBUG=True
in Ihrer Datei settings.py
vorhanden ist, werden Aufgaben synchron ausgeführt, genau wie normale Funktionsaufrufe. Dies soll verhindern, dass während der Entwicklung oder Ausführung von Tests sowohl Redis als auch ein zusätzlicher Verbraucherprozess ausgeführt werden. Weitere Informationen hierzu finden Sie hier .
Dazu müssen wir die folgende Zeile in settings.py
hinzufügen:
HUEY = {}
Wenn Sie dieses Verhalten jedoch überschreiben möchten, können Sie stattdessen die folgende Huey-Konfiguration hinzufügen:
HUEY = { "immediate": False }
Wenn Sie über die oben in settings.py
erwähnte Konfiguration verfügen und DEBUG=True
haben, fordert Huey Sie auf, Redis einzurichten und Huey Worker mit dem Befehl run_huey
auszuführen.
Einige Beobachtungen zu Huey im Vergleich zu Celery sind:
run_huey
nur einen Dienst ausführen müssen.