Então, hoje falarei sobre uma alternativa ao Celery chamada Huey , que vem com uma configuração muito mais fácil do que o Celery e é muito menor em tamanho comparado ao Celery.
A razão pela qual decidi experimentar o Huey é porque às vezes enfrentei alguns problemas com o Celery ao realizar algumas tarefas comuns porque a documentação não é muito boa.
Para quem não sabe o que é Celery ou nunca o usou antes, Huey é uma fila de tarefas assíncronas que permite executar tarefas agendadas ou de longa duração em segundo plano.
Estaremos instalando os seguintes pacotes:
O blog a seguir vem acompanhado de um repositório GitHub que você pode usar para testar o projeto de demonstração que iremos criar.
Clique aqui para ver o repositório.
Abra o terminal e digite o seguinte para criar um diretório; você pode pular esta etapa e fazer isso no próprio File Explorer.
mkdir huey_demo
Vamos criar primeiro um virtualenv para instalar as dependências do nosso projeto:
python -m venv venv
Ative o virtualenv (Linux):
source venv/bin/activate
Digite o seguinte comando no terminal para instalar todas as dependências:
pip install Django==4.0.4 redis==4.2.2 huey==2.4.3
No momento em que escrevo este artigo, essas foram as versões com as quais testei esta configuração. Fique de olho no repositório do Github para obter quaisquer atualizações da versão mais recente no futuro.
Crie o projeto Django digitando o seguinte comando no terminal:
django-admin startproject django_huey_demo
Mude o diretório para o diretório do projeto Django:
cd django_huey_demo
Crie o aplicativo em nosso projeto:
python manage.py startapp demo
Inclua o aplicativo criado no projeto settings.py
, faça as seguintes alterações:
INSTALLED_APPS = [ # Existing Apps "demo.apps.DemoConfig", # <== Add this line ]
Defina o modo de depuração como False
em settings.py
:
DEBUG=False
Estamos definindo Debug como False para que possamos ver como Huey funciona em produção, falaremos mais sobre isso mais tarde.
Agora que terminamos de configurar nosso projeto, é um bom momento para falar sobre o que construiremos hoje.
Buscaremos a "Palavra do Dia" diariamente na API do Wordnik . Em seguida, armazenaremos a palavra, sua definição e um exemplo da palavra em uma frase em nosso banco de dados.
Configuraremos uma tarefa periódica usando Huey que irá buscar a Palavra do Dia e armazená-la.
Para armazenar a palavra estaremos criando um modelo Django da mesma.
Você pode seguir este guia para obter a chave API.
Precisamos adicionar Huey aos aplicativos instalados em nosso projeto, então faça as seguintes alterações no arquivo settings.py
:
INSTALLED_APPS = [ # Existing apps 'huey.contrib.djhuey', # <== Add this line ]
Precisamos instalar o Redis for Huey para armazenar informações sobre tarefas na fila, como costumávamos fazer com o Celery. Você pode consultar o link a seguir para instalar o Redis com base em seu sistema operacional específico.
Se você se sentir confortável em usar o Docker, poderá usar o seguinte comando:
docker run --name redis_huey -p 6379:6379 -d redis
Por padrão, Huey tentará se conectar ao servidor Redis em execução em localhost:6379
. Se não estiver presente, ocorrerá um erro.
Adicione o seguinte código ao seu arquivo 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
Faça migrações:
python manage.py makemigrations demo
Aplicar migrações:
python manage.py migrate demo
Crie um arquivo chamado tasks.py
no diretório do aplicativo de demonstração. A razão pela qual nomeamos nosso arquivo tasks.py
é para ajudar Huey a descobrir automaticamente as tarefas presentes em nossos aplicativos registrados. Se nomeássemos nosso arquivo com outro nome, teríamos que registrar manualmente nossa tarefa. Se quiser saber mais, você pode conferir a documentação do Huey aqui .
Antes de escrevermos a definição da tarefa, precisamos instalar requests
de dependência adicionais. Instale-o digitando o seguinte em seu terminal:
pip install requests==2.27.1
Agora vem o código:
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"] )
Adicione a seguinte linha nas configurações do seu projeto:
WORDNIK_API_KEY = "api-key-here"
Este bloco de código pode ser muito difícil de entender, então vamos examinar tudo nele um por um:
Huey Decorador
from huey.contrib.djhuey import db_periodic_task
Este é um decorador fornecido pela Huey para registrar tarefas periódicas que envolvem o trabalho com o banco de dados, este decorador fecha automaticamente a conexão com o banco de dados após a conclusão da tarefa, para mais detalhes, você pode consultar aqui.
Cronograma Crontab
@db_periodic_task(crontab(hour="18", minute="00"))
Estamos passando o argumento crontab(hour="18", minute="00")
para nosso decorador de tarefas periódicas, isso diz a Huey para executar nossa tarefa às 18h todos os dias. Você pode usar este site para criar suas programações de crontab, eu sempre uso.
Chave API do Wordnik
from django.conf import settings # Usage ## settings.WORDNIK_API_KEY
from django.conf import settings
é a maneira padrão de importar quaisquer dados das configurações do nosso projeto, é útil nos casos em que temos vários arquivos de configurações configurados para ambientes diferentes para que ele saiba qual arquivo escolher sem que tenhamos que nos preocupar isto. Ele descobre qual arquivo de configurações estamos usando a partir da variável de ambiente DJANGO_SETTINGS_MODULE
. Mas você não precisa se preocupar com esses detalhes.
Em seguida, usamos a chave em nossa chamada de API do Wordnik.
Chamada de API Wordnik
r = requests.get( f"https://api.wordnik.com/v4/words.json/wordOfTheDay?api_key={settings.WORDNIK_API_KEY}")
Aqui, estamos usando o módulo requests para fazer uma solicitação GET para a API Wordnik enquanto passamos nossa chave API para autenticação.
Armazenando palavra no banco de dados
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"] )
Depois de analisar a resposta da API, armazenamos a definição da palavra em nosso banco de dados. Estamos usando o método get_or_create
em vez do método create
aqui para não criarmos múltiplas cópias da mesma palavra em nosso banco de dados se essa palavra for repetida pela API do Wordnik.
Resposta da API Wordnik
Esta é a aparência da resposta da API Wordnik para o endpoint Word of the Day. Algumas das seções irrelevantes da resposta foram truncadas por questões de brevidade.
{ "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... }
Você pode iniciar o trabalhador Huey digitando o seguinte comando em seu terminal:
python manage.py run_huey
Você pode passar vários sinalizadores para o comando acima, o que alterará o que é registrado no console, como:
-v, --verbose
- registro detalhado (inclui nível DEBUG)-q, --quiet
– registro mínimo-S, --simple
- formato de registro simples (“mensagem de tempo”)
Para ver várias outras opções de registro, confira a documentação aqui .
Huey vem com vários decoradores de tarefas, dependendo de quais operações você está executando na tarefa.
Explicarei resumidamente o que todos eles fazem abaixo.
Aqui está a declaração de importação para todos os decoradores:
from huey.contrib.djhuey import task, periodic_task, db_task, db_periodic_task
task
: Uma tarefa regular.periodic_task
: quando você deseja executar uma tarefa periodicamente com base em um agendamento.db_task
: quando você deseja executar operações de banco de dados em sua tarefa.db_periodic_task
: quando você deseja executar operações de banco de dados em uma tarefa periódica.Deixe-me mostrar mais alguns exemplos de como você pode usar o crontab para agendar suas tarefas.
crontab(minute='*/3')
agendaria a tarefa para ser executada a cada três minutos.crontab(hour='*/3', minute='5')
criaria uma tarefa que será executada 5 minutos após cada terceira hora.crontab(minute='00', hour='10', month='*/2', day_of_week='*/5')
criaria uma tarefa que seria executada a cada 5º dia da semana, de cada 2º mês às 10:00 DA MANHÃ. Por exemplo, você tem a seguinte tarefa definida em tasks.py
:
from huey.contrib.djhuey import task @task() def count(): for i in range(10): print(i)
Agora, se você deseja chamar esta tarefa, mas deseja que ela seja executada após 5 segundos, você pode fazer o seguinte:
count.schedule(delay=5)
O parâmetro delay
assume valores em segundos, portanto, se você deseja que ele seja executado após 5 minutos, especifique 300 segundos.
Suponha que você adicione a seguinte lógica à nossa tarefa existente:
@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"] )
Assim, adicionamos a lógica para verificar o código de status da resposta, e se for diferente de 200, ele tentará novamente a tarefa até 2 vezes. Mas essas novas tentativas aconteceriam sem qualquer intervalo de tempo entre as duas tentativas. Agora, e se você quiser atrasar várias tentativas desta tarefa? Podemos fazer isso passando o argumento retry_delay
, ele aceita valores em segundos.
@db_periodic_task(crontab(hour="18", minute="00"), retries=2, retry_delay=10)
Isso causará um atraso de 10 segundos entre várias tentativas.
Huey vem com uma configuração padrão que facilita o trabalho com Huey durante o desenvolvimento no Django. Portanto, sempre que você tiver DEBUG=True
presente em seu arquivo settings.py
, as tarefas serão executadas de forma síncrona, como chamadas de função normais. O objetivo disso é evitar a execução do Redis e de um processo de consumidor adicional durante o desenvolvimento ou execução de testes. Você pode ler mais sobre isso aqui .
Para isso, precisamos adicionar a seguinte linha em settings.py
:
HUEY = {}
No entanto, se quiser substituir esse comportamento, você pode adicionar a seguinte configuração do Huey:
HUEY = { "immediate": False }
Se você tiver a configuração acima mencionada em settings.py
, embora tenha DEBUG=True
, Huey exigirá que você configure o Redis e execute o Huey Worker usando o comando run_huey
.
Algumas observações sobre o Huey em comparação com o Aipo são:
run_huey
.