Criar controladores de tarefas

Esta página descreve como criar um processador de tarefas, o código que processa uma tarefa push. Tem de fornecer um controlador de pedidos para processar a tarefa. O mapeamento do URL do pedido para o controlador adequado é declarado no app.yaml do seu serviço, tal como qualquer outro controlador de pedidos. Uma vez que controla como mapear os pedidos de tarefas para um controlador, pode organizar os seus controladores de tarefas como quiser. Se a sua aplicação processar muitos tipos diferentes de tarefas, pode adicionar todos os processadores a um único serviço ou distribuí-los por vários serviços.

Escrever um controlador de pedidos de tarefas push

Na fila, o serviço Task Queue cria um cabeçalho HTTP e envia-o para uma instância do serviço de trabalho especificado pelo destino da tarefa. Os pedidos da fila de tarefas são enviados a partir do endereço IP 0.1.0.2.

O seu controlador não tem de ser escrito no mesmo idioma que criou e colocou a tarefa na fila se o controlador estiver num serviço separado.

Quando escrever o controlador, siga estas diretrizes:

  • O código tem de devolver um código de estado HTTP no intervalo de 200 a 299 para indicar êxito. Qualquer outro código indica que a tarefa falhou.

  • As tarefas de envio têm um prazo de conclusão fixo que depende do tipo de escalabilidade do serviço que as está a executar. Os serviços de escalabilidade automática têm de terminar antes de decorridos 10 minutos. Os serviços de escalabilidade manual e básica podem ser executados durante um máximo de 24 horas. Se o seu controlador não cumprir o prazo, o serviço Task Queue assume que a tarefa falhou e vai tentar novamente.

    Quando o tempo de execução de uma tarefa se aproxima do prazo, o App Engine gera um erro DeadlineExceededError (do módulo google.appengine.runtime) antes de o prazo ser atingido, para que possa guardar o seu trabalho ou registar o progresso realizado.

  • O controlador tem de ser idempotente. A API Task Queue do App Engine foi concebida para fornecer uma entrega "pelo menos uma vez"; ou seja, se uma tarefa for adicionada com êxito, o App Engine vai entregá-la a um controlador, pelo menos, uma vez. Tenha em atenção que, em algumas circunstâncias raras, é possível a execução de várias tarefas, pelo que o seu código tem de garantir que não existem efeitos secundários prejudiciais da execução repetida.

O exemplo seguinte demonstra como obter um valor inteiro de um pedido e adicionar o valor a um contador mantido no Cloud Datastore:


from google.appengine.ext import ndb
import webapp2


COUNTER_KEY = 'default counter'


class Counter(ndb.Model):
    count = ndb.IntegerProperty(indexed=False)


class UpdateCounterHandler(webapp2.RequestHandler):
    def post(self):
        amount = int(self.request.get('amount'))

        # This task should run at most once per second because of the datastore
        # transaction write throughput.
        @ndb.transactional
        def update_counter():
            counter = Counter.get_or_insert(COUNTER_KEY, count=0)
            counter.count += amount
            counter.put()

        update_counter()


app = webapp2.WSGIApplication([
    ('/update_counter', UpdateCounterHandler)
], debug=True)

O mapeamento do URL da tarefa /update-counter para a classe UpdateCounterHandler é feito em WSGIApplication.

O ficheiro worker.yaml cria um serviço denominado "worker" e adiciona-lhe o código do worker. Tenha em atenção que o URL do controlador é seguro porque especifica login:admin:

runtime: python27
api_version: 1
threadsafe: true
service: worker

handlers:
- url: /.*
  script: worker.app
  login: admin

A fila de tarefas usa o código HTTP na resposta do controlador para determinar se a tarefa foi bem-sucedida. A resposta do controlador é vista apenas pelo serviço Task Queue e apenas para determinar se a tarefa foi bem-sucedida. A fila ignora todos os outros campos na resposta. Em seguida, o serviço rejeita a resposta. A app de origem nunca recebe nenhum dos dados. Se uma tarefa falhar, o serviço Task Queue tenta novamente a tarefa enviando outro pedido.

Os dados fornecidos pelo utilizador podem ser enviados para o controlador no pedido como uma string de consulta ou como uma carga útil no corpo do pedido. A inserção de dados do utilizador é descrita no artigo Criar tarefas. Se o pedido incluir dados, o controlador tem de saber como foram inseridos no pedido. O código exato que usa para obter os dados do pedido depende da framework Web específica que está a usar.

Para testar um controlador de tarefas, inicie sessão como administrador e visite o URL do controlador no navegador.

Ler cabeçalhos de pedidos

Um pedido HTTP de tarefa de envio tem cabeçalhos especiais definidos pelo App Engine, que contêm informações específicas da tarefa que o seu controlador pode usar.

Se estes cabeçalhos estiverem presentes num pedido de um utilizador externo à sua app, são removidos e substituídos. A única exceção é para pedidos de administradores com sessão iniciada na aplicação, que podem definir cabeçalhos para fins de teste. Por outro lado, os cabeçalhos não são removidos quando a sua app está a ser executada no servidor de desenvolvimento.

Os pedidos da fila de tarefas contêm sempre os seguintes cabeçalhos:

Cabeçalho Descrição
X-Appengine-QueueName O nome da fila (possivelmente "default" para a fila de envio predefinida).
X-Appengine-TaskName O nome da tarefa ou um ID exclusivo gerado pelo sistema se não tiver sido especificado um nome.
X-Appengine-TaskRetryCount O número de vezes que esta tarefa foi repetida. Para a primeira tentativa, este valor é 0. Este número inclui tentativas em que a tarefa falhou devido à falta de instâncias disponíveis e nunca atingiu a fase de execução.
X-Appengine-TaskExecutionCount O número de vezes que esta tarefa falhou anteriormente durante a fase de execução. Este número não inclui falhas devido à falta de instâncias disponíveis.
X-Appengine-TaskETA O tempo de execução alvo da tarefa, especificado em segundos desde 1 de janeiro de 1970.

Se o seu controlador de pedidos encontrar algum dos cabeçalhos indicados acima, pode confiar que o pedido é um pedido da fila de tarefas.

Além disso, os pedidos da fila de tarefas podem conter os seguintes cabeçalhos:

Cabeçalho Descrição
X-Appengine-TaskPreviousResponse O código de resposta HTTP da nova tentativa anterior.
X-Appengine-TaskRetryReason O motivo da repetição da tarefa.
X-Appengine-FailFast Indica que uma tarefa em execução falha imediatamente se não estiver disponível uma instância existente.

Proteger URLs de controladores de tarefas

Se uma tarefa realizar operações confidenciais (como modificar dados), é recomendável proteger o URL do controlador para impedir que um utilizador externo malicioso o chame diretamente. Pode impedir que os utilizadores acedam a URLs de tarefas restringindo o acesso aos administradores do App Engine. Os próprios pedidos de tarefas são emitidos pelo App Engine e podem sempre segmentar um URL restrito.

Pode restringir um URL adicionando o elemento login: admin à configuração do controlador no ficheiro app.yaml.

Por exemplo:

handlers:
- url: /your-task
  script: worker.app
  login: admin

O que se segue?