Nesta página, descrevemos como criar tarefas e colocá-las em filas push. Quando quiser processar uma tarefa, você precisará criar um novo objeto de tarefa e colocá-lo em uma fila. É possível especificar explicitamente o serviço e o gerenciador que processam a tarefa e, como opção, passar dados específicos da tarefa para o gerenciador. Também é possível ajustar a configuração da tarefa, como agendá-la caso ela precise ser executada posteriormente ou limitar o número de vezes que a tarefa será repetida se falhar.
Como criar uma nova tarefa
Para criar e enfileirar uma tarefa, chame a função taskqueue.add().
O código a seguir cria uma tarefa que segmenta o serviço chamado worker
e invoca o gerenciador definindo o URL /update-counter
:
Outra opção é criar um objeto Task e chamar o método add() dele.
Como especificar o serviço de worker
Quando uma tarefa é retirada da fila, o serviço de fila de tarefas a envia para um serviço de worker. Cada tarefa tem um destino e um url, que determinam o serviço e o gerenciador que realizarão a tarefa.
target
O destino especifica o serviço que receberá a solicitação HTTP para executar a tarefa. É uma string que especifica um serviço/versão/instância em qualquer uma das formas canônicas. As formas mais usadas são estas:
service
version.service
instance.version.service
A string de destino precede o nome de domínio do aplicativo. Há três maneiras de definir o destino de uma tarefa:
Declarar o destino ao construir a tarefa. É possível definir o destino explicitamente usando o parâmetro
target
na função taskqueue.add(). Veja o exemplo acima.Incluir uma diretiva
target
ao definir uma fila emqueue.yaml
, como na definição dequeue-blue
. Todas as tarefas incluídas em uma fila com umtarget
terão esse destino, mesmo que outro destino seja atribuído à tarefa no momento da criação.Se nenhum destino for especificado de acordo com um dos dois métodos anteriores, o destino da tarefa será a versão do serviço que a põe em fila. Se você colocar em fila uma tarefa do serviço e versão padrões dessa maneira, e a versão padrão mudar antes da execução da tarefa, esta será executada na nova versão padrão.
url
Com url
, um dos gerenciadores no serviço de destino é selecionado para a execução da tarefa.
O url
precisa corresponder a um dos padrões de URL do gerenciador no serviço de destino. O url
poderá incluir parâmetros de consulta se o método especificado na tarefa for GET
ou PULL
. Se nenhum url
for especificado, será usado o URL /_ah/queue/[QUEUE_NAME]
padrão, em que [QUEUE_NAME]
corresponde ao nome da fila da tarefa.
Como passar dados ao gerenciador
É possível passar dados como parâmetros de consulta ao gerenciador no URL da tarefa, mas somente se o método especificado na tarefa for GET
ou PULL
.
payload
, que entrega dados de tarefas no corpo da solicitação HTTP.params
Essas três chamadas são equivalentes:
taskqueue.add(method=GET, url='/update-counter?key=blue', target='worker')
taskqueue.add(url='/update-counter', params={'key': 'blue'}, target='worker')
taskqueue.add(url='/update-counter', payload="{'key': 'blue'}", target='worker')
Como nomear uma tarefa
Quando você cria uma nova tarefa, o App Engine atribui a ela um nome exclusivo por padrão. Porém, é possível atribuir à tarefa um nome de sua escolha usando o parâmetro name
. Uma vantagem de escolher os nomes que serão atribuídos às tarefas é a remoção de duplicações, o que significa que é possível usar os nomes de tarefas para garantir que a tarefa seja adicionada apenas uma vez. A remoção de duplicações continua por nove dias após a conclusão ou exclusão da tarefa.
Observe que essa lógica de remoção de duplicações apresenta uma sobrecarga de desempenho significativa, resultando em maiores latências e taxas de erro potencialmente maiores associadas a tarefas nomeadas. Esses custos poderão aumentar significativamente se os nomes das tarefas forem sequenciais, como no caso de carimbos de data/hora. Então, se você mesmo atribuir os nomes, recomendamos usar um prefixo bem distribuído para nomes de tarefas, como um hash do conteúdo.
Se você mesmo atribuir nomes às tarefas, observe que o comprimento máximo do nome é 500 caracteres. O nome pode conter letras maiúsculas e minúsculas, sublinhados de números e hifens.
taskqueue.add(url='/url/path', name='first-try')
Como adicionar tarefas de maneira assíncrona
Por padrão, as chamadas que adicionam tarefas a filas são síncronas. As chamadas síncronas funcionam bem na maioria dos cenários. Adicionar uma tarefa a uma fila costuma ser uma operação rápida. O tempo médio para adicionar uma tarefa é de menos de 5 ms. Porém, uma pequena porcentagem dessas operações pode demorar muito mais tempo.
Não é possível colocar em lote as operações de adição de tarefas a filas diferentes. Por isso, a API Task Queue também fornece chamadas assíncronas que permitem adicionar essas tarefas em paralelo, minimizando ainda mais essa latência. Esse recurso é útil para a criação de um aplicativo muito sensível à latência que precisa executar diversas operações de adição de tarefas a diferentes filas ao mesmo tempo.
Se você quiser fazer chamadas assíncronas para uma fila de tarefas, use os métodos assíncronos fornecidos pela classe Queue e um objeto RPC. Chame get_result()
no
objeto RPC
retornado para forçar a conclusão da solicitação. Ao adicionar tarefas
de maneira assíncrona em uma transação, você deve chamar get_result()
no objeto RPC
antes de confirmar a transação para garantir que a solicitação foi concluída.
Como enfileirar tarefas em transações do Cloud Datastore
É possível enfileirar uma tarefa como parte de uma transação do Datastore, de modo que ela seja enfileirada e garantida para ser enfileirada apenas se a transação for confirmada. As tarefas adicionadas a uma transação são consideradas parte dela e têm o mesmo nível de isolamento e consistência.
Um aplicativo não pode inserir mais de cinco tarefas transacionais a filas de tarefas durante uma única transação. Tarefas transacionais não podem ter nomes especificados pelo usuário.
O exemplo de código a seguir demonstra como inserir tarefas transacionais em uma fila push como parte de uma transação do Datastore:
from google.appengine.api import taskqueue
from google.appengine.ext import ndb
@ndb.transactional
def do_something_in_transaction():
taskqueue.add(url='/path/to/my/worker', transactional=True)
#...
do_something_in_transaction()
Como usar a biblioteca de tarefas adiadas em vez de um serviço de worker
A configuração de um gerenciador para cada tarefa distinta (conforme descrito nas seções
anteriores) pode ser complicada. A serialização e desserialização de argumentos
complexos para a tarefa também pode ter complicações, especialmente se tiver muitas tarefas diversas, porém, pequenas,
que você queira executar na fila. O SDK para Python inclui uma biblioteca (google.appengine.ext.deferred
) que expõe uma função simples que permite evitar todo o trabalho de configuração de gerenciadores de tarefas dedicados e serializar e desserializar seus parâmetros.
Para usar esta biblioteca, você precisa adicionar o deferred
integrado a app.yaml
. Para
mais informações, consulte a
seção Gerenciadores incorporados da
referência app.yaml
.
Para usar a biblioteca deferred
, basta transmitir a função e os argumentos dela para
deferred.defer()
:
import logging
from google.appengine.ext import deferred
def do_something_expensive(a, b, c=None):
logging.info("Doing something expensive!")
# Do your work here
# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, True)
A biblioteca deferred
empacota a chamada de função e os argumentos dela e a adiciona
à fila de tarefas. Quando a tarefa é executada, a biblioteca deferred
executa do_something_expensive("Hello, world!", 42, True)
.
Como trabalhar com tarefas em um aplicativo multilocatário
Por padrão, as filas push usam o namespace atual configurado no gerenciador de namespace no momento da criação da tarefa. Se o aplicativo usar multilocação, consulte a API Namespaces para Python 2.
A seguir
- Saiba como criar gerenciadores de tarefas.