Witajcie! Dziś porozmawiamy sobie o asynchronicznych zadaniach w Django.
Przygotowałem dla Was serię trzech postów, które przeprowadzą Was przez meandry Celery w Django. Czemu akurat trzy? Materiału jest spora ilość, a przyjemności należy sobie dawkować 🙂
W pierwszym poście rzucimy okiem na podstawy Celery - co to w ogóle jest, do czego się tego używa i jak to ugryźć w Django. Drugi wpis to już konkret - praktyczne przykłady, tricki i pułapki, na które możecie wpaść. A na deser? Alternatywy! Bo może Celery to nie zawsze najlepsze rozwiązanie?
Zaczynamy!
Czym jest Celery?
Celery to narzędzie służące do wykonywania zadań asynchronicznych, czyli takich, które mogą być realizowane w tle, niezależnie od głównego procesu aplikacji. W kontekście Django oznacza to, że możemy odciążyć naszą aplikację od czasochłonnych operacji, takich jak wysyłanie e-maili, generowanie raportów, przetwarzanie obrazów czy komunikacja z zewnętrznymi API. Celery działa w oparciu o system kolejek zadań, gdzie zadania są umieszczane w kolejce i przetwarzane przez specjalne procesy zwane workerami.
Zastosowania Celery w Django
W klasycznym cyklu request-response(zapytanie - odpowiedź) aplikacje webowe muszą przetwarzać każde żądanie użytkownika w czasie rzeczywistym. Jeśli żądanie wymaga wykonania skomplikowanego zadania (np. przetwarzania dużych danych), może to znacząco wydłużyć czas odpowiedzi i obniżyć wydajność aplikacji. W skrajnych przypadkach dostaniecie błąd 500 spowodowany przekroczeniem czasu żądania. Celery pozwala na przeniesienie takich operacji do tła, dzięki czemu:
- Aplikacja pozostaje responsywna i szybka.
- Można wykonywać zadania równolegle na wielu serwerach, co zwiększa skalowalność.
- Użytkownicy nie muszą czekać na zakończenie długotrwałych operacji.
Celery jest szczególnie przydatne w projektach, które wymagają obsługi dużej liczby użytkowników lub złożonych procesów w tle. Oto kilka konkretnych zastosowań:
Przetwarzanie długotrwałych zadań w tle
Niektóre operacje w aplikacjach Django mogą zajmować dużo czasu, co mogłoby spowolnić działanie serwera lub wydłużyć czas odpowiedzi dla użytkownika. Dzięki Celery takie zadania, jak wysyłanie e-maili, przetwarzanie dużych plików czy komunikacja z zewnętrznymi API, mogą być wykonywane w tle, bez wpływu na główny proces aplikacji.Okresowe zadania (cron-like)
Celery umożliwia łatwe planowanie zadań, które muszą być wykonywane regularnie. Dzięki dodatkowi Celery Beat możesz skonfigurować harmonogram dla takich operacji jak codzienne raporty, synchronizacja danych czy automatyczne czyszczenie bazy danych. Celery Beat działa podobnie do systemowego crona, ale jest w pełni zintegrowany z Celery i pozwala zarządzać zadaniami bezpośrednio w aplikacji. Jeśli zarządzanie zadaniami z poziomu aplikacji nie jest konieczne, są prostsze alternatywy.Obsługa kolejek zadań
Celery pozwala na tworzenie wielu kolejek, dzięki czemu możesz przypisywać różne priorytety do różnych typów zadań. Na przykład:- Kolejka "wysoki priorytet" dla natychmiastowych powiadomień,
- Kolejka "niski priorytet" dla operacji wymagających dużych zasobów, takich jak analiza danych.
Taka organizacja pozwala na lepsze wykorzystanie workerów i unikanie sytuacji, w których mniej istotne zadania blokują te kluczowe.
Rozproszenie obciążenia na wiele serwerów
W przypadku dużych projektów Celery umożliwia uruchamianie workerów na wielu maszynach. Każdy worker może obsługiwać inną kolejkę lub współdzielić zadania z innymi. Dzięki temu można skalować system horyzontalnie, co zwiększa jego wydajność i niezawodność. Rozproszone środowisko sprawdza się szczególnie dobrze w aplikacjach o wysokim obciążeniu lub wymagających przetwarzania dużych ilości danych.
Architektura Celery
Celery opiera się na trzech głównych komponentach, które współpracują w celu realizacji asynchronicznych zadań:
1. Klient (Producer)
Klient to część Twojej aplikacji Django, która tworzy zadania i umieszcza je w kolejce. W Django zadania są definiowane za pomocą dekoratora @app.task
(lub @shared_task
, jeśli zadanie ma być współdzielone między aplikacjami). Klient wysyła zadania do brokera, który przechowuje je do czasu przetworzenia przez workera.
2. Broker (Message Broker)
Broker to system pośredniczący, który przechowuje zadania w kolejce i przekazuje je do workerów. Najczęściej używane brokery to:
- Redis – szybki, prosty w konfiguracji i popularny w mniejszych projektach.
- RabbitMQ – bardziej zaawansowany, odpowiedni dla dużych systemów wymagających wysokiej niezawodności.
Broker działa jak "przekaźnik", ale sam nie wykonuje zadań – tylko je przechowuje i dystrybuuje.
3. Worker (Consumer)
Worker to proces, który pobiera zadania z brokera i je wykonuje. Może działać na tym samym serwerze co aplikacja Django lub na zupełnie innym urządzeniu. Workery mogą być uruchamiane równolegle na wielu maszynach, co pozwala na skalowanie aplikacji.
Diagram architektury Celery:
źródło: https://muktar.tech/a-guide-to-using-celery-with-django-for-background-processing-fb14e6c4a299
Konfiguracja Celery w projekcie Django
Instalacja niezbędnych pakietów
Aby rozpocząć pracę z Celery, musisz zainstalować odpowiednie pakiety w swoim środowisku Django. Najczęściej używanym brokerem wiadomości jest Redis, więc instalacja obejmuje zarówno Celery, jak i bibliotekę Redis.
Zainstaluj Celery i Redis:
pip install celery[redis]
Alternatywnie możesz dodać te zależności do pliku
requirements.txt
:celery==5.4.0 redis==5.2.1
Następnie zainstaluj je za pomocą:
pip install -r requirements.txt
Upewnij się, że Redis jest zainstalowany i uruchomiony na Twoim serwerze:
sudo apt update sudo apt install redis sudo systemctl start redis
Podstawowa konfiguracja (settings.py, celery.py)
1. Plik celery.py
Utwórz plik celery.py
w katalogu głównym projektu (tam, gdzie znajduje się settings.py
i wsgi.py
). Ten plik będzie zawierał konfigurację Celery:
import os
from celery import Celery
# Ustawienie domyślnego modułu ustawień Django dla aplikacji Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celery_blog.settings')
app = Celery('celery_blog')
# Ładowanie konfiguracji z pliku settings.py z prefiksem CELERY_
app.config_from_object('django.conf:settings', namespace='CELERY')
# Automatyczne wykrywanie zadań we wszystkich aplikacjach Django
app.autodiscover_tasks()
2. Plik __init__.py
W tym samym katalogu co celery.py
, edytuj plik __init__.py
, aby upewnić się, że aplikacja Celery zostanie załadowana przy starcie projektu:
from .celery import app as celery_app
__all__ = ['celery_app']
3. Konfiguracja w settings.py
Dodaj ustawienia Celery do pliku settings.py
. Oto przykład konfiguracji przy użyciu Redisa jako brokera i backendu wyników:
# Adres brokera (Redis)
CELERY_BROKER_URL = 'redis://localhost:6379/0'
# Backend wyników (Redis)
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
# Opcjonalne ustawienia
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'
Jeśli Twój Redis działa na innym porcie lub maszynie, dostosuj adres w CELERY_BROKER_URL
.
Uruchamianie workera Celery
Po skonfigurowaniu projektu możesz uruchomić proces workera, który będzie odpowiedzialny za przetwarzanie zadań w tle:
W terminalu przejdź do katalogu głównego projektu Django.
Uruchom worker za pomocą polecenia:
celery -A celery_blog worker --loglevel=info
Jeśli chcesz jednocześnie uruchomić Celery Beat (do obsługi okresowych zadań), w nowym oknie terminala użyj dodatkowego procesu:
celery -A celery_blog beat --loglevel=info
Worker powinien teraz nasłuchiwać na zadania dodane do kolejki i przetwarzać je w tle.
Dzięki tej konfiguracji Twój projekt Django jest gotowy do korzystania z Celery! W kolejnych krokach możesz definiować zadania i testować ich działanie w praktyce. Uwaga: to jest naprawde testowy setup. W normalnych warunkach projekt byłby zapewne oparty na Docker Compose z Celery jako jedna z usług.
Przykład użycia Celery w Django
Poniżej znajdziesz kompletny przykład implementacji zadania Celery w projekcie Django, oparty na widokach klasowych (class-based views), wraz z odpowiednimi zmianami w pliku urls.py
. Przykład obejmuje stworzenie zadania, uruchamianie go, sprawdzanie statusu oraz wyników.
Definiowanie zadania
Utwórz plik tasks.py
w katalogu aplikacji (np. core
) i zdefiniuj proste zadanie Celery:
from celery import shared_task
import time
@shared_task
def example_task(duration):
"""Proste zadanie symulujące długotrwały proces."""
time.sleep(duration) # Symulacja opóźnienia
return f"Zadanie zakończone po {duration} sekundach"
Dekorator @shared_task
sprawia, że zadanie jest dostępne dla Celery i może być wywoływane w dowolnym miejscu w projekcie.
Tworzenie widoków opartych na klasach
Widok do uruchamiania zadania
Utwórz widok, który dodaje zadanie do kolejki i zwraca jego identyfikator, w pliku views.py
from django.http import JsonResponse
from django.views import View
from core.tasks import example_task
class RunTaskView(View):
"""
UWAGA: by to zadziałało, zakomentuj: "django.middleware.csrf.CsrfViewMiddleware", w settings.py
"""
def post(self, request, *args, **kwargs):
# Uruchomienie zadania asynchronicznego
duration = int(request.POST.get("duration", 5)) # Pobranie czasu z żądania (domyślnie 5 sekund)
result = example_task.delay(duration) # Zadanie dodane do kolejki
return JsonResponse({"task_id": result.id, "status": "Task started"})
Widok do sprawdzania statusu zadania
Dodaj widok umożliwiający sprawdzenie statusu i wyniku zadania na podstawie jego identyfikatora:
from celery.result import AsyncResult
class TaskStatusView(View):
def get(self, request, task_id, *args, **kwargs):
# Pobranie informacji o statusie zadania
result = AsyncResult(task_id)
response = {"task_id": task_id, "status": result.status}
if result.ready(): # Jeśli zadanie zostało zakończone
response["result"] = result.get() # Pobranie wyniku
return JsonResponse(response)
Konfiguracja URL-i
Dodaj odpowiednie ścieżki w pliku urls.py
aplikacji (celery_blog/urls.py
):
from django.urls import path
from core.views import RunTaskView, TaskStatusView
urlpatterns = [
path('run-task/', RunTaskView.as_view(), name='run-task'), # Endpoint do uruchamiania zadania
path('task-status/<str:task_id>/', TaskStatusView.as_view(), name='task-status'), # Endpoint do sprawdzania statusu
]
Testowanie działania
Uruchom Redis i worker Celery
Przed testowaniem upewnij się, że Redis działa i worker Celery jest uruchomiony:
Uruchom Redis:
sudo systemctl start redis
ruchom workera Celery:
celery -A celery_blog worker --loglevel=info
Uruchom serwer Django
W nowym oknie terminala uruchom serwer Django:
python manage.py runserver
Testowanie za pomocą narzędzi takich jak Postman lub cURL
1. Uruchomienie zadania
Wykonaj żądanie POST na endpoint /run-task/
, podając opcjonalny parametr duration
(czas trwania w sekundach). Przykład z użyciem cURL:
curl -X POST -d "duration=10" http://127.0.0.1:8000/run-task/
Otrzymasz odpowiedź z identyfikatorem zadania:
{
"task_id": "e7f8c9b4-2f3a-4b9c-8a6d-2d3e5c6a7f89",
"status": "Task started"
}
Jeśli zwróciło błąd, zakomentuj: "django.middleware.csrf.CsrfViewMiddleware", w settings.py. Bez obaw, to jest testowy projekt.
2. Sprawdzanie statusu zadania
Wykonaj żądanie GET na endpoint /task-status/<task_id>/
, podając identyfikator zwrócony wcześniej:
curl http://127.0.0.1:8000/task-status/e7f8c9b4-2f3a-4b9c-8a6d-2d3e5c6a7f89/
Otrzymasz odpowiedź z aktualnym statusem:
- Jeśli zadanie jest w trakcie realizacji:
{ "task_id": "e7f8c9b4-2f3a-4b9c-8a6d-2d3e5c6a7f89", "status": "PENDING" }
Jeśli zostało zakończone:
{ "task_id": "e7f8c9b4-2f3a-4b9c-8a6d-2d3e5c6a7f89", "status": "SUCCESS", "result": "Zadanie zakończone po 10 sekundach" }
Statusy mogą mieć wartości takie jak:
PENDING – zadanie czeka na wykonanie,
STARTED – zadanie jest wykonywane,
SUCCESS – zadanie zostało zakończone pomyślnie,
FAILURE – wystąpił błąd podczas wykonywania.
Dzięki temu kompletnemu przykładowi masz działające środowisko Celery w Django, które obsługuje zarówno uruchamianie zadań asynchronicznych, jak i monitorowanie ich statusów oraz wyników!
Podsumowanie
W tym poście poznaliśmy podstawy konfiguracji Celery w projekcie Django oraz stworzyliśmy kompletny przykład prostego zadania asynchronicznego. Wiesz już, jak zainstalować niezbędne pakiety, skonfigurować Celery, uruchomić workera oraz zintegrować zadania z aplikacją Django za pomocą widoków opartych na klasach. Dzięki temu Twoja aplikacja może teraz wykonywać długotrwałe operacje w tle, pozostając responsywną dla użytkowników.
W kolejnym poście skupimy się na praktycznych aspektach pracy z Celery. Omówimy, jak tworzyć bardziej zaawansowane zadania, zarządzać wynikami, monitorować ich status oraz radzić sobie z błędami i wyjątkami. Dowiesz się również, jakie są najlepsze praktyki przy pracy z Celery, aby maksymalnie wykorzystać jego możliwości. Do zobaczenia w następnym wpisie!
Kod projektu jest dostępny na: https://github.com/pymasterspl/celery_blog. W repozytorium użyłem Poetry, w poście, dla ułatwienia, requirements. Nie ma znaczenia jakiego managera środowisk wirtualnych użyjecie.
Dołącz do społeczności PyMasters, gdzie możesz wziąć udział w ciekawych projektach i podnosić swoje umiejętności w Pythonie i Django.
Pobierz mojego bezpłanego ebooka: WARSZTAT JUNIORA Przewodnik po kluczowych kompetencjach i narzędziach dla początkującego programisty Pythona
Zapraszam do zadawania pytań przez formularz kontaktowy. Pamiętaj, że jeśli potrzebujesz wsparcia, możesz napisać do mnie - pomogę.
Spodobał Ci się post?
Podziel się nim!
Masz uwagi do posta, chcesz porozmawiać, szukasz pomocy z Pythonem i Django? Napisz do mnie!