Criar gerenciadores de tarefas

Nesta página, descrevemos como criar um gerenciador de tarefas, o código que processa uma tarefa push. É preciso fornecer um gerenciador de solicitações para processá-la. O mapeamento do URL da solicitação para o gerenciador apropriado é declarado no app.yaml do serviço, assim como qualquer outro gerenciador de solicitações. Uma vez que controla como mapear solicitações de tarefa para um gerenciador, você tem a liberdade para organizar o gerenciador de tarefas. Se o aplicativo processar muitos tipos diferentes de tarefas, adicione todos os gerenciadores a um único serviço ou distribuí-los entre vários serviços.

Como gravar um gerenciador de solicitações de tarefa por push

O serviço de fila de tarefas cria um cabeçalho HTTP e o envia para uma instância do serviço de trabalho especificado pelo destino da tarefa. As solicitações da fila de tarefas são enviadas do endereço IP 0.1.0.2.

Se o gerenciador estiver em um serviço separado, ele não precisará ser escrito na mesma linguagem em que a tarefa foi criada e enfileirada.

Ao gravar o gerenciador, siga estas diretrizes:

  • O código precisa retornar um código de status HTTP no intervalo 200-299 para indicar o sucesso. Qualquer outro código indica que a tarefa falhou.

  • As tarefas de push têm um prazo de conclusão fixo que depende do tipo de dimensionamento do serviço que os executa. Os serviços de dimensionamento automático precisam terminar em 10 minutos. Os serviços de dimensionamento manual e básico podem ser executados em até 24 horas. Se o gerenciador perde o prazo, o serviço fila de tarefas pressupõe que a tarefa falhou e tentará novamente.

    Quando a execução de uma tarefa se aproxima do tempo limite, o App Engine gera um DeadlineExceededError (do módulo google.appengine.runtime) antes de terminar o prazo. Assim, é possível salvar o trabalho ou registrar qualquer progresso.

  • O gerenciador precisa ser idempotente. A API Task Queue do App Engine foi projetada para entrega "pelo menos uma vez". Se uma tarefa tiver sido adicionada, o App Engine vai entregá-la para o gerenciador pelo menos uma vez. Em algumas circunstâncias, é possível executar várias tarefas. Dessa maneira, o código precisa garantir que a execução repetida não causará efeitos colaterais prejudiciais.

No exemplo a seguir, veja como recuperar um valor inteiro de uma solicitação 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 dentro de WSGIApplication.

O arquivo worker.yaml cria um serviço chamado "worker" e adiciona o código do worker a ele. O URL do manipulador é 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 gerenciador para determinar se a tarefa foi bem-sucedida. A resposta do manipulador é vista somente pelo serviço de fila de tarefas e apenas para determinar isso. Ela ignora todos os outros campos na resposta. Em seguida, o serviço descarta a resposta. O aplicativo de origem nunca recebe nenhum dado. Se uma tarefa falhar, o serviço repete a tarefa enviando outra solicitação.

Os dados inseridos pelo usuário podem ser enviados ao gerenciador na solicitação como uma string de consulta ou como um payload no corpo da solicitação. A inserção de dados do usuário é descrita em Como criar tarefas. Se a solicitação incluir dados, o gerenciador precisará saber como eles foram inseridos na solicitação. O código exato que você usa para buscar os dados da solicitação depende do framework da Web específico que você está usando.

Para testar um gerenciador de tarefas, faça login como administrador e visite o URL do gerenciador no navegador.

Como ler cabeçalhos de solicitação

Uma solicitação HTTP de tarefa push tem cabeçalhos especiais definidos pelo App Engine, que contêm informações específicas da tarefa que o gerenciador pode usar.

Se eles estiverem em uma solicitação de usuário externo para o aplicativo, serão removidos e substituídos. A única exceção é para solicitações de administradores conectados do aplicativo, que podem definir cabeçalhos para fins de teste. Por outro lado, os cabeçalhos não são removidos quando o aplicativo é executado no servidor de desenvolvimento.

As solicitações da fila de tarefas sempre contêm os cabeçalhos:

Cabeçalho Descrição
X-Appengine-QueueName O nome da fila (possivelmente "padrão" para a fila push padrão).
X-Appengine-TaskName O nome da tarefa ou um código exclusivo gerado pelo sistema caso nenhum nome tenha sido especificado.
X-Appengine-TaskRetryCount O número de novas tentativas para a tarefa. Para a primeira tentativa, esse valor é 0. Esse número inclui tentativas em que a tarefa falhou por falta de instâncias disponíveis e nunca chegou à fase de execução.
X-Appengine-TaskExecutionCount O número de vezes em que essa tarefa falhou anteriormente durante a execução. Esse número não inclui falhas por causa de uma falta de instâncias disponíveis.
X-Appengine-TaskETA O tempo de execução desejado da tarefa, especificado em segundos desde 1º de janeiro de 1970.

Se encontrar algum dos cabeçalhos listados acima, o gerenciador de solicitações poderá confiar que se trata de uma solicitação da fila de tarefas.

Além disso, as solicitações da fila de tarefas podem conter os seguintes cabeçalhos:

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

Como proteger URLs do gerenciador de tarefas

Se uma tarefa executar operações confidenciais (como modificar dados), convém proteger o URL do gerenciador para evitar que um usuário externo mal-intencionado chame-o diretamente. Você pode evitar que usuários acessem URLs da tarefa restringindo o acesso aos administradores do App Engine. As próprias solicitações de tarefas são emitidas pelo App Engine e podem sempre segmentar um URL restrito.

É possível restringir um URL adicionando o elemento login: admin para a configuração do gerenciador no arquivo app.yaml.

Exemplo:

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

A seguir