Tarefas em segundo plano¶
Você pode definir tarefas em segundo plano a serem executadas _ após _ retornar uma resposta.
Isso é útil para operações que precisam acontecer após uma solicitação, mas que o cliente realmente não precisa esperar a operação ser concluída para receber a resposta.
Isso inclui, por exemplo:
- Envio de notificações por email após a realização de uma ação:
- Como conectar-se a um servidor de e-mail e enviar um e-mail tende a ser "lento" (vários segundos), você pode retornar a resposta imediatamente e enviar a notificação por e-mail em segundo plano.
- Processando dados:
- Por exemplo, digamos que você receba um arquivo que deve passar por um processo lento, você pode retornar uma resposta de "Aceito" (HTTP 202) e processá-lo em segundo plano.
Usando BackgroundTasks
¶
Primeiro, importe BackgroundTasks
e defina um parâmetro em sua função de operação de caminho com uma declaração de tipo de BackgroundTasks
:
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_notification(email: str, message=""):
with open("log.txt", mode="w") as email_file:
content = f"notification for {email}: {message}"
email_file.write(content)
@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, email, message="some notification")
return {"message": "Notification sent in the background"}
O FastAPI criará o objeto do tipo BackgroundTasks
para você e o passará como esse parâmetro.
Criar uma função de tarefa¶
Crie uma função a ser executada como tarefa em segundo plano.
É apenas uma função padrão que pode receber parâmetros.
Pode ser uma função async def
ou def
normal, o FastAPI saberá como lidar com isso corretamente.
Nesse caso, a função de tarefa gravará em um arquivo (simulando o envio de um e-mail).
E como a operação de gravação não usa async
e await
, definimos a função com def
normal:
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_notification(email: str, message=""):
with open("log.txt", mode="w") as email_file:
content = f"notification for {email}: {message}"
email_file.write(content)
@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, email, message="some notification")
return {"message": "Notification sent in the background"}
Adicionar a tarefa em segundo plano¶
Dentro de sua função de operação de caminho, passe sua função de tarefa para o objeto tarefas em segundo plano com o método .add_task()
:
from fastapi import BackgroundTasks, FastAPI
app = FastAPI()
def write_notification(email: str, message=""):
with open("log.txt", mode="w") as email_file:
content = f"notification for {email}: {message}"
email_file.write(content)
@app.post("/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
background_tasks.add_task(write_notification, email, message="some notification")
return {"message": "Notification sent in the background"}
.add_task()
recebe como argumentos:
- Uma função de tarefa a ser executada em segundo plano (
write_notification
). - Qualquer sequência de argumentos que deve ser passada para a função de tarefa na ordem (
email
). - Quaisquer argumentos nomeados que devem ser passados para a função de tarefa (
mensagem = "alguma notificação"
).
Injeção de dependência¶
Usar BackgroundTasks
também funciona com o sistema de injeção de dependência, você pode declarar um parâmetro do tipo BackgroundTasks
em vários níveis: em uma função de operação de caminho, em uma dependência (confiável), em uma subdependência, etc.
O FastAPI sabe o que fazer em cada caso e como reutilizar o mesmo objeto, de forma que todas as tarefas em segundo plano sejam mescladas e executadas em segundo plano posteriormente:
from typing import Union
from fastapi import BackgroundTasks, Depends, FastAPI
app = FastAPI()
def write_log(message: str):
with open("log.txt", mode="a") as log:
log.write(message)
def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
if q:
message = f"found query: {q}\n"
background_tasks.add_task(write_log, message)
return q
@app.post("/send-notification/{email}")
async def send_notification(
email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)
):
message = f"message to {email}\n"
background_tasks.add_task(write_log, message)
return {"message": "Message sent"}
Neste exemplo, as mensagens serão gravadas no arquivo log.txt
após o envio da resposta.
Se houver uma consulta na solicitação, ela será gravada no log em uma tarefa em segundo plano.
E então outra tarefa em segundo plano gerada na função de operação de caminho escreverá uma mensagem usando o parâmetro de caminho email
.
Detalhes técnicos¶
A classe BackgroundTasks
vem diretamente de starlette.background
.
Ela é importada/incluída diretamente no FastAPI para que você possa importá-la do fastapi
e evitar a importação acidental da alternativa BackgroundTask
(sem o s
no final) de starlette.background
.
Usando apenas BackgroundTasks
(e não BackgroundTask
), é então possível usá-la como um parâmetro de função de operação de caminho e deixar o FastAPI cuidar do resto para você, assim como ao usar o objeto Request
diretamente.
Ainda é possível usar BackgroundTask
sozinho no FastAPI, mas você deve criar o objeto em seu código e retornar uma Starlette Response
incluindo-o.
Você pode ver mais detalhes na documentação oficiais da Starlette para tarefas em segundo plano .
Ressalva¶
Se você precisa realizar cálculos pesados em segundo plano e não necessariamente precisa que seja executado pelo mesmo processo (por exemplo, você não precisa compartilhar memória, variáveis, etc), você pode se beneficiar do uso de outras ferramentas maiores, como Celery .
Eles tendem a exigir configurações mais complexas, um gerenciador de fila de mensagens/tarefas, como RabbitMQ ou Redis, mas permitem que você execute tarefas em segundo plano em vários processos e, especialmente, em vários servidores.
Para ver um exemplo, verifique os Geradores de projeto, todos incluem celery já configurado.
Mas se você precisa acessar variáveis e objetos do mesmo aplicativo FastAPI, ou precisa realizar pequenas tarefas em segundo plano (como enviar uma notificação por e-mail), você pode simplesmente usar BackgroundTasks
.
Recapitulando¶
Importe e use BackgroundTasks
com parâmetros em funções de operação de caminho e dependências para adicionar tarefas em segundo plano.