Como usar a fila de tarefas do App Engine (tarefas push) em aplicativos Flask (módulo 7)

1. Visão geral

A série de codelabs da estação de migração sem servidor (tutoriais práticos e individualizados) e os vídeos relacionados têm como objetivo ajudar desenvolvedores sem servidor do Google Cloud a modernizar apps, orientando-os em uma ou mais migrações, principalmente para evitar serviços legados. Isso torna seus apps mais portáteis e oferece mais opções e flexibilidade, o que permite a integração e o acesso a uma variedade maior de produtos do Cloud e o upgrade para versões de idiomas mais recentes com mais facilidade. Embora inicialmente voltada para os primeiros usuários do Cloud, principalmente desenvolvedores do App Engine (ambiente padrão), esta série é ampla o suficiente para incluir outras plataformas sem servidor, como o Cloud Functions e o Cloud Run, ou outros lugares, se aplicável.

Este codelab ensina a usar tarefas push da fila de tarefas do App Engine no app de exemplo do codelab do módulo 1. A postagem do blog e o vídeo do módulo 7 complementam este tutorial, fornecendo uma breve visão geral do conteúdo dele.

Neste módulo, vamos adicionar o uso de tarefas push e migrar esse uso para o Cloud Tasks no módulo 8 e posteriores para o Python 3 e o Cloud Datastore no módulo 9. Aqueles que usam filas de tarefas para tarefas pull migrarão para o Cloud Pub/Sub e devem consultar os módulos 18 a 19.

Você vai aprender a

  • Usar o serviço pacote/API Task Queue do App Engine
  • Adicionar o uso da tarefa de push a um app Python 2 Flask básico do App Engine MapReduce

O que é necessário

Pesquisa

Como você vai usar este tutorial?

Apenas leitura Ler e fazer os exercícios

Como você classificaria sua experiência com Python?

Iniciante Intermediário Proficiente

Como você classificaria sua experiência de uso dos serviços do Google Cloud?

Iniciante Intermediário Proficiente

2. Contexto

A Fila de Tarefas do App Engine oferece suporte a tarefas push e pull. Para melhorar a portabilidade de aplicativos, a equipe do Google Cloud recomenda migrar de serviços em pacote legados, como a Fila de tarefas, para outros serviços independentes do Cloud ou equivalentes de terceiros.

A migração de tarefas pull é abordada nos módulos de migração 18 a 19, enquanto os módulos 7 a 9 focam na migração de tarefas push. Para migrar das tarefas push da Fila de tarefas do App Engine, adicione o uso delas ao app Flask e do App Engine NFS resultante do codelab do módulo 1. Nesse aplicativo, uma nova visualização de página registra uma nova visita e exibe as visitas mais recentes ao usuário. Como as visitas mais antigas nunca são mostradas novamente e ocupam espaço no Datastore, criaremos uma tarefa push para excluir automaticamente as visitas mais antigas. A seguir, no Módulo 8, vamos migrar esse app da fila de tarefas para o Cloud Tasks.

Este tutorial apresenta as seguintes etapas:

  1. Configuração/Pré-trabalho
  2. Atualizar a configuração
  3. Modificar o código do aplicativo

3. Configuração/Pré-trabalho

Esta seção explica como:

  1. Configurar seu projeto do Cloud
  2. Receber app de amostra do valor de referência
  3. (Re)implantar e validar o app de referência

Essas etapas garantem que você está começando com o código em funcionamento.

1. Configurar projeto

Se você concluiu o codelab do módulo 1, recomendamos reutilizar o mesmo projeto e código. Outra opção é criar um novo projeto ou reutilizar um projeto existente. Verifique se o projeto tem uma conta de faturamento ativa e se o App Engine está ativado.

2. Receber app de amostra do valor de referência

Um dos pré-requisitos deste codelab é ter um app do Módulo 1 do App Engine em funcionamento: conclua o codelab do módulo 1 (recomendado) ou copie o app do módulo 1 do repositório. Não importa se você usa o seu ou o nosso, o código do Módulo 1 é onde vamos "INICIAR". Este codelab orienta você em cada etapa, concluindo com um código semelhante ao que está na pasta de repositório "FINISH" do Módulo 7.

Independentemente do app do Módulo 1 usado, a pasta será semelhante à mostrada abaixo, possivelmente também com uma pasta lib:

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. (Re) Implantar aplicativo de referência

Siga as etapas abaixo para (re)implantar o app do Módulo 1:

  1. Exclua a pasta lib, se houver uma, e execute: pip install -t lib -r requirements.txt para preencher lib novamente. Pode ser necessário usar o comando pip2 se você tiver o Python 2 e o 3 instalados.
  2. Verifique se você instalou e inicializou a ferramenta de linha de comando gcloud e analisou o uso dela.
  3. Defina seu projeto do Cloud com gcloud config set project PROJECT_ID se você não quiser inserir o PROJECT_ID com cada comando gcloud emitido.
  4. Implante o app de exemplo com gcloud app deploy
  5. Confirme se o app Módulo 1 é executado conforme o esperado, sem problemas para mostrar as visitas mais recentes (ilustrados abaixo).

a7a9d2b80d706a2b.png

4. Atualizar a configuração

Nenhuma alteração é necessária nos arquivos de configuração padrão do App Engine (app.yaml, requirements.txt, appengine_config.py).

5. Modificar arquivos do aplicativo

O arquivo principal do aplicativo é main.py, e todas as atualizações nesta seção são referentes a esse arquivo. Há também uma pequena atualização no modelo da Web, templates/index.html. Estas são as mudanças que precisam ser implementadas nesta seção:

  1. Atualizar importações
  2. Adicionar tarefa push
  3. Adicionar gerenciador de tarefas
  4. Atualizar modelo da Web

1. Atualizar importações

Uma importação de google.appengine.api.taskqueue ativa a funcionalidade da fila de tarefas. Alguns pacotes da biblioteca padrão do Python também são necessários:

  • Como estamos adicionando uma tarefa para excluir as visitas mais antigas, o app vai precisar lidar com carimbos de data/hora, o que significa o uso de time e datetime.
  • Para registrar informações úteis sobre a execução da tarefa, precisamos de logging.

Depois de adicionar todas essas importações, o código ficará como antes e depois das mudanças:

ANTES:

from flask import Flask, render_template, request
from google.appengine.ext import ndb

DEPOIS:

from datetime import datetime
import logging
import time
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb

2. Adicionar tarefa push (coletar dados para a tarefa, enfileirar nova tarefa)

A documentação da fila push afirma: "Para processar uma tarefa, você precisa adicioná-la a uma fila push. O App Engine fornece uma fila push padrão, chamada default, que está configurada e pronta para uso com as configurações padrão. Se quiser, basta adicionar todas as tarefas à fila padrão, sem precisar criar e configurar outras filas." Este codelab usa a fila default para simplificar. Para saber mais sobre como definir suas próprias filas push, com características iguais ou diferentes, consulte a documentação Como criar filas push.

O objetivo principal deste codelab é adicionar uma tarefa à fila push default que tem como função excluir visitas antigas do Datastore que não são mais exibidas. O app de referência registra cada visita (solicitação de GET para /) criando uma nova entidade Visit. Em seguida, busca e mostra as visitas mais recentes. Nenhuma das visitas mais antigas será mostrada ou usada novamente. Portanto, a tarefa push exclui todas as visitas anteriores à visita mais antiga exibida. Para fazer isso, o comportamento do app precisa mudar um pouco:

  1. Ao consultar as visitas mais recentes, em vez de retornar essas visitas imediatamente, modifique o app para salvar o carimbo de data/hora da última Visit, a mais antiga exibida. É seguro excluir todas as visitas anteriores a esse.
  2. Crie uma tarefa push com esse carimbo de data/hora como payload e direcione-a para o gerenciador de tarefas, acessível por meio de um POST HTTP para /trim. Especificamente, use utilitários padrão do Python para converter o carimbo de data/hora do Datastore e enviá-lo (como um ponto flutuante) à tarefa, mas também registrá-lo (como uma string) e retornar essa string como um valor sentinela a ser exibido ao usuário.

Tudo isso acontece no fetch_visits(). Esta é a aparência do processo antes e depois das atualizações:

ANTES:

def fetch_visits(limit):
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))

DEPOIS:

def fetch_visits(limit):
    'get most recent visits and add task to delete older visits'
    data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    taskqueue.add(url='/trim', params={'oldest': oldest})
    return (v.to_dict() for v in data), oldest_str

3. Adicionar gerenciador de tarefas (código chamado quando a tarefa é executada)

Embora a exclusão de visitas antigas pudesse ser realizada facilmente no fetch_visits(), essa funcionalidade não tem muito a ver com o usuário final. Ela é uma funcionalidade auxiliar e é uma boa candidata para processamento assíncrono fora das solicitações de app padrão. O usuário final aproveitará os benefícios de consultas mais rápidas, porque haverá menos informações no Datastore. Crie uma nova função trim(), chamada por uma solicitação POST da fila de tarefas para /trim, que vai fazer o seguinte:

  1. Extrai a "visita mais antiga" payload de carimbo de data/hora
  2. Emite uma consulta ao Datastore para encontrar todas as entidades mais antigas que esse carimbo de data/hora.
  3. Opta por uma versão mais rápida "somente chaves" porque nenhum dado real do usuário é necessário.
  4. Registra o número de entidades a serem excluídas (incluindo zero).
  5. Chama ndb.delete_multi() para excluir qualquer entidade (ignorado se não for).
  6. Retorna uma string vazia (junto com um código de retorno HTTP 200 implícito).

Você pode conferir tudo isso em trim() abaixo. Adicione-o a main.py logo após fetch_visits():

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = request.form.get('oldest', type=float)
    keys = Visit.query(
            Visit.timestamp < datetime.fromtimestamp(oldest)
    ).fetch(keys_only=True)
    nkeys = len(keys)
    if nkeys:
        logging.info('Deleting %d entities: %s' % (
                nkeys, ', '.join(str(k.id()) for k in keys)))
        ndb.delete_multi(keys)
    else:
        logging.info('No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

4. Atualizar modelo da Web

Atualize o modelo da Web, templates/index.html, com essa condicional Jinja2 para exibir o carimbo de data/hora mais antigo se essa variável existir:

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}

Adicione esse snippet após a lista de visitas exibida, mas antes de fechar o corpo para que seu modelo fique assim:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}
</body>
</html>

6. Resumo/limpeza

Esta seção encerra este codelab implantando o app, verificando se ele funciona conforme o esperado e em qualquer saída refletida. Após a validação do app, faça uma limpeza e considere as próximas etapas.

Implante e verifique o aplicativo

Implante o app com gcloud app deploy. A saída precisa ser idêntica à do app Módulo 1, com exceção de uma nova linha na parte de baixo que mostra quais visitas serão excluídas:

4aa8a2cb5f527079.png

Parabéns por concluir o codelab. Seu código agora precisa corresponder ao que está na pasta de repositório do módulo 7. Agora ele está pronto para migrar para o Cloud Tasks no Módulo 8.

Limpar

Geral

Se você já tiver terminado por enquanto, recomendamos que desative seu aplicativo do App Engine para evitar cobranças. No entanto, se você quiser fazer mais testes, saiba que a plataforma do App Engine tem uma cota sem custo financeiro e, desde que você não exceda esse nível de uso, não haverá cobranças. Isso é para computação, mas também pode haver cobranças por serviços relevantes do App Engine. Portanto, consulte a página de preços para mais informações. Se essa migração envolver outros serviços do Cloud, eles serão faturados separadamente. Em ambos os casos, se aplicável, consulte a seção "Específico para este codelab". seção abaixo.

Para divulgação completa, a implantação em uma plataforma de computação sem servidor do Google Cloud, como o App Engine, incorre em menores custos de criação e armazenamento. O Cloud Build tem a própria cota sem custo financeiro, assim como o Cloud Storage. O armazenamento da imagem consome parte da cota. No entanto, talvez você more em uma região que não tenha esse nível sem custo financeiro, portanto, esteja ciente do uso do armazenamento para minimizar os possíveis custos. "Pastas" específicas do Cloud Storage que você deve analisar incluem:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Os links de armazenamento acima dependem do PROJECT_ID e da *LOC*ação, por exemplo, "us" caso seu app esteja hospedado nos EUA.

Por outro lado, se você não for continuar com este aplicativo ou outros codelabs de migração relacionados e quiser excluir tudo completamente, encerre seu projeto.

Específicos deste codelab

Os serviços listados abaixo são exclusivos deste codelab. Consulte a documentação de cada produto para mais informações:

Próximas etapas

Nessa "migração", você adicionou o uso da fila push da fila de tarefas ao app de exemplo do Módulo 1, adicionando suporte ao rastreamento de visitantes, o que resultou no app de exemplo do Módulo 7. Na próxima migração, você vai aprender a fazer o upgrade das tarefas push do App Engine para o Cloud Tasks, caso queira. A partir do segundo semestre de 2021, os usuários não precisarão mais migrar para o Cloud Tasks ao fazer upgrade para o Python 3. Leia mais sobre isso na próxima seção.

Se você quiser migrar para o Cloud Tasks, o codelab do módulo 8 é a próxima etapa. Além disso, há outras migrações a serem consideradas, como Cloud Datastore, Cloud Memorystore, Cloud Storage ou Cloud Pub/Sub (filas pull). Há também migrações entre produtos para o Cloud Run e o Cloud Functions. Todo o conteúdo da estação de migração sem servidor (codelabs, vídeos, código-fonte [quando disponível]) pode ser acessado no repositório de código aberto correspondente.

7. Migração para o Python 3

No terceiro trimestre de 2021, a equipe do App Engine ampliou o suporte a muitos dos serviços incluídos para ambientes de execução de segunda geração (originalmente disponíveis apenas em ambientes de execução de 1a geração). Isso significa que você não precisa mais migrar de serviços em pacote, como a fila de tarefas do App Engine, para o Cloud independente ou equivalentes de terceiros, como o Cloud Tasks, ao transferir seu aplicativo para o Python 3. Em outras palavras, é possível continuar usando a fila de tarefas em aplicativos do App Engine para Python 3, desde que você adapte o código para acessar serviços agrupados em ambientes de execução de última geração.

Saiba como migrar o uso de serviços agrupados para o Python 3 no codelab do módulo 17 e no vídeo correspondente. Embora esse tópico esteja fora do escopo do Módulo 7, os links abaixo estão versões Python 3 dos aplicativos dos Módulos 1 e 7 transferidos para Python 3 e ainda usando o Node Engine e a Fila de tarefas do App Engine.

8. Outros recursos

Abaixo estão listados recursos adicionais para desenvolvedores que querem explorar melhor esse Módulo de migração ou o relacionado, assim como produtos relacionados. Isso inclui locais para fornecer feedback sobre esse conteúdo, links para o código e várias documentações que podem ser úteis.

Problemas/feedback do codelab

Se você encontrar problemas com este codelab, pesquise seu problema antes de preenchê-lo. Links para pesquisar e criar novos problemas:

Recursos de migração

Os links para as pastas do repositório do Módulo 2 (START) e Módulo 7 (FINISH) podem ser encontrados na tabela abaixo.

Codelab

Python 2

Python 3

Módulo 1

código

code (não apresentado neste tutorial)

Módulo 7 (este codelab)

código

code (não apresentado neste tutorial)

Recursos on-line

Veja abaixo recursos on-line que podem ser relevantes para este tutorial:

Filas de tarefas do App Engine

Plataforma do App Engine

Outras informações sobre a nuvem

Vídeos

Licença

Este conteúdo está sob a licença Atribuição 2.0 Genérica da Creative Commons.