Итак, сегодня я буду говорить об альтернативе Celery под названием Huey , которая гораздо проще в настройке, чем Celery, и намного меньше по размеру по сравнению с Celery.
Причина, по которой я решил попробовать Huey, заключается в том, что иногда я сталкивался с некоторыми проблемами с Celery при выполнении некоторых общих задач, поскольку документация не слишком хороша.
Для тех, кто не знает, что такое Celery, или не использовал его раньше, Huey — это асинхронная очередь задач, которая позволяет выполнять запланированные задачи или длительные задачи в фоновом режиме.
Мы будем устанавливать следующие пакеты:
Следующий блог сопровождается репозиторием GitHub, который вы можете использовать для тестирования демонстрационного проекта, который мы будем создавать.
Нажмите здесь, чтобы просмотреть репо.
Откройте терминал и введите следующее, чтобы создать каталог; вы можете пропустить этот шаг и сделать это из самого проводника.
mkdir huey_demo
Давайте сначала создадим virtualenv для установки зависимостей нашего проекта:
python -m venv venv
Активируйте virtualenv (Linux):
source venv/bin/activate
Введите следующую команду в терминале, чтобы установить все зависимости:
pip install Django==4.0.4 redis==4.2.2 huey==2.4.3
На момент написания этой статьи это были версии, с которыми я тестировал эту настройку, следите за репозиторием Github на предмет любых обновлений в соответствии с последней версией в будущем.
Создайте проект Django, введя в терминале следующую команду:
django-admin startproject django_huey_demo
Измените каталог на каталог проекта Django:
cd django_huey_demo
Создайте приложение в рамках нашего проекта:
python manage.py startapp demo
Включите созданное приложение в проект settings.py
, внесите следующие изменения:
INSTALLED_APPS = [ # Existing Apps "demo.apps.DemoConfig", # <== Add this line ]
Установите для режима отладки значение False
в settings.py
:
DEBUG=False
Мы устанавливаем для Debug значение False, чтобы мы могли видеть, как Huey работает в рабочей среде, подробнее об этом позже.
Теперь, когда мы закончили настройку нашего проекта, самое время рассказать вам о том, что мы будем строить сегодня.
Мы будем ежедневно получать «Слово дня» из Wordnik API . Затем мы сохраним слово, его определение и пример слова в предложении в нашей базе данных.
Мы создадим периодическую задачу с помощью Huey, которая будет получать «Слово дня» и сохранять его.
Для хранения слова мы создадим его модель Django.
Вы можете следовать этому руководству , чтобы получить ключ API.
Нам нужно добавить Хьюи в установленные приложения нашего проекта, поэтому внесите следующие изменения в файл settings.py
:
INSTALLED_APPS = [ # Existing apps 'huey.contrib.djhuey', # <== Add this line ]
Нам нужно установить Redis для Huey, чтобы хранить в нем информацию о задачах в очереди, как мы это делали с Celery. Вы можете перейти по следующей ссылке , чтобы установить Redis в зависимости от вашей конкретной операционной системы.
Если вам удобно использовать Docker, вы можете использовать следующую команду:
docker run --name redis_huey -p 6379:6379 -d redis
По умолчанию Хьюи попытается подключиться к серверу Redis, работающему на localhost:6379
. Если его нет, это вызовет ошибку.
Добавьте следующий код в файл demo/models.py
:
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
Сделайте миграцию:
python manage.py makemigrations demo
Примените миграции:
python manage.py migrate demo
Создайте файл с именем tasks.py
в каталоге демонстрационного приложения. Причина, по которой мы назвали наш файл tasks.py
заключается в том, чтобы помочь Хьюи автоматически обнаруживать задачи, присутствующие в наших зарегистрированных приложениях. Если бы мы назвали наш файл иначе, нам пришлось бы вручную зарегистрировать нашу задачу. Если вы хотите узнать больше, вы можете ознакомиться с документацией Хьюи здесь .
Прежде чем писать определение задачи, нам необходимо установить дополнительные requests
зависимостей. Установите его, набрав в терминале следующее:
pip install requests==2.27.1
Теперь идет код:
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"] )
Добавьте следующую строку в настройки вашего проекта:
WORDNIK_API_KEY = "api-key-here"
Этот блок кода может оказаться очень сложным для понимания, поэтому давайте рассмотрим его поочередно:
Хьюи Декоратор
from huey.contrib.djhuey import db_periodic_task
Это декоратор, предоставляемый Huey для регистрации периодических задач, связанных с работой с базой данных. Этот декоратор автоматически закрывает соединение с базой данных после завершения задачи. Более подробную информацию можно найти здесь.
Расписание Кронтаба
@db_periodic_task(crontab(hour="18", minute="00"))
Мы передаем аргумент crontab(hour="18", minute="00")
нашему декоратору периодической задачи, это говорит Хьюи запускать нашу задачу в 18:00 каждый день. Вы можете использовать этот веб-сайт для создания расписаний crontab, я использую его каждый раз.
Ключ API Wordnik
from django.conf import settings # Usage ## settings.WORDNIK_API_KEY
from django.conf import settings
— это стандартный способ импорта любых данных из настроек нашего проекта. Это полезно в тех случаях, когда у нас есть несколько файлов настроек, настроенных для разных сред, поэтому он будет знать, какой файл выбрать, и нам не придется беспокоиться об этом. это. Он определяет, какой файл настроек мы используем, из переменной среды DJANGO_SETTINGS_MODULE
. Но вам не нужно беспокоиться об этих деталях.
Затем мы используем ключ в нашем вызове API Wordnik.
Вызов API Wordnik
r = requests.get( f"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key={settings.WORDNIK_API_KEY}")
Здесь мы используем модуль запросов для отправки запроса GET к API Wordnik, передавая наш ключ API для аутентификации.
Хранение слова в базе данных
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"] )
После анализа ответа API мы сохраняем определение слова в нашей базе данных. Здесь мы используем метод get_or_create
вместо метода create
, чтобы не создавать несколько копий одного и того же слова в нашей базе данных, если это слово когда-либо повторяется API Wordnik.
Ответ API Wordnik
Вот как выглядит ответ API Wordnik для конечной точки Word of the Day. Некоторые из нерелевантных разделов ответа были сокращены в целях краткости.
{ "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... }
Вы можете запустить рабочий Huey, введя в терминале следующую команду:
python manage.py run_huey
Вы можете передать несколько флагов приведенной выше команде, которая изменит то, что регистрируется на консоли, например:
-v, --verbose
— подробное журналирование (включая уровень DEBUG)-q, --quiet
— минимальное журналирование-S, --simple
— простой формат логирования («сообщение времени»)
Чтобы просмотреть различные другие варианты ведения журнала, ознакомьтесь с документацией здесь .
Huey поставляется с несколькими декораторами задач в зависимости от того, какие операции вы выполняете внутри задачи.
Ниже я кратко объясню, что все это делает.
Вот оператор импорта для всех декораторов:
from huey.contrib.djhuey import task, periodic_task, db_task, db_periodic_task
task
: обычная задача.periodic_task
: если вы хотите периодически запускать задачу по расписанию.db_task
: если вы хотите выполнять операции с БД в рамках своей задачи.db_periodic_task
: если вы хотите выполнять операции с БД в рамках периодической задачи.Позвольте мне показать вам еще несколько примеров того, как вы можете использовать crontab для планирования задач.
crontab(minute='*/3')
запланирует выполнение задачи каждые три минуты.crontab(hour='*/3', minute='5')
создаст задачу, которая будет запускаться через 5 минут каждого третьего часа.crontab(minute='00', hour='10', month='*/2', day_of_week='*/5')
создаст задачу, которая будет запускаться каждый 5-й день недели каждого 2-го месяца в 10:00 УТРА. Например, у вас есть следующая задача, определенная внутри tasks.py
:
from huey.contrib.djhuey import task @task() def count(): for i in range(10): print(i)
Теперь, если вы хотите вызвать эту задачу, но хотите, чтобы она запускалась через 5 секунд, вы можете сделать следующее:
count.schedule(delay=5)
Параметр delay
принимает значения в секундах, поэтому, если вы хотите, чтобы он выполнялся через 5 минут, укажите 300 секунд.
Предположим, вы добавите следующую логику в нашу существующую задачу:
@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"] )
Итак, мы добавили логику для проверки кода состояния ответа, и если он отличается от 200, задача будет повторяться до двух раз. Но эти повторные попытки будут происходить без какого-либо временного разрыва между двумя попытками. А что, если вы хотите отложить несколько попыток выполнения этой задачи? Мы можем сделать это, передав аргумент retry_delay
, он принимает значения в секундах.
@db_periodic_task(crontab(hour="18", minute="00"), retries=2, retry_delay=10)
Это приведет к 10-секундной задержке между несколькими попытками.
Хьюи поставляется с настройками по умолчанию, что упрощает работу с Хьюи во время разработки в Django. Таким образом, всякий раз, когда в вашем файле settings.py
присутствует DEBUG=True
, задачи будут выполняться синхронно, как и обычные вызовы функций. Целью этого является избежание запуска как Redis, так и дополнительного потребительского процесса во время разработки или выполнения тестов. Подробнее об этом можно прочитать здесь .
Для этого нам нужно добавить следующую строку в settings.py
:
HUEY = {}
Однако, если вы хотите переопределить это поведение, вы можете вместо этого добавить следующую конфигурацию Хьюи:
HUEY = { "immediate": False }
Если у вас есть вышеуказанная конфигурация, указанная в settings.py
, и DEBUG=True
, Huey потребует от вас настроить Redis и запустить Huey Worker с помощью команды run_huey
.
Некоторые наблюдения о Хьюи по сравнению с Сельдереем:
run_huey
.