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 Serverless Migration Station (tutoriais práticos e autoguiados) e os vídeos relacionados têm como objetivo ajudar os desenvolvedores sem servidor do Google Cloud a modernizar os aplicativos orientando-os em uma ou mais migrações, principalmente a migração de serviços legados. Isso torna seus apps mais portáteis e oferece mais opções e flexibilidade, permitindo que você se integre e acesse uma variedade maior de produtos do Cloud e faça upgrade mais fácil para versões de linguagem mais recentes. Embora o foco inicial seja nos 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 em outro lugar, 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 de blog e o vídeo do módulo 7 complementam este tutorial, oferecendo uma breve visão geral do conteúdo.

Neste módulo, vamos adicionar o uso de tarefas de push e migrar esse uso para o Cloud Tasks no módulo 8 e, depois, para o Python 3 e o Cloud Datastore no módulo 9. Quem usa filas de tarefas para tarefas pull vai migrar para o Cloud Pub/Sub e deve consultar os módulos 18 e 19.

Você vai aprender a

  • Usar a API/serviço agrupado da fila de tarefas do App Engine
  • Adicionar o uso de tarefas push a um app básico do Python 2 Flask App Engine NDB

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 é compatível com tarefas push e pull. Para melhorar a portabilidade do aplicativo, a equipe do Google Cloud recomenda migrar de serviços legados em pacote, como a fila de tarefas, para outros serviços autônomos do Cloud ou equivalentes de terceiros.

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

Este tutorial inclui 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ê esteja começando com um código funcional.

1. Configurar projeto

Se você concluiu o codelab do Módulo 1, recomendamos reutilizar esse mesmo projeto e código. Se preferir, crie um novo projeto ou reutilize outro. 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 para este codelab é ter um app do App Engine do Módulo 1 em funcionamento. Conclua o codelab do Módulo 1 (recomendado) ou copie o app do Módulo 1 do repositório. Independentemente de você usar o nosso ou o seu, o código do Módulo 1 é o que vamos "COMEÇAR". Este codelab orienta você em cada etapa, concluindo com um código semelhante ao que está na pasta "FINISH" do repositório do Módulo 7.

Independente do app do Módulo 1 que você usar, a pasta vai ser parecida com a abaixo, possivelmente com uma pasta lib também:

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

3. (Re) Implantar aplicativo de referência

Siga estas etapas 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. Talvez seja 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 revisou o uso dela.
  3. Defina seu projeto na nuvem com gcloud config set project PROJECT_ID se não quiser inserir seu PROJECT_ID com cada comando gcloud emitido.
  4. Implante o app de exemplo com gcloud app deploy
  5. Confirme se o app do módulo 1 está funcionando como esperado, sem problemas ao mostrar as visitas mais recentes (ilustrado abaixo).

a7a9d2b80d706a2b.png

4. Atualizar a configuração

Não é necessário fazer mudanças 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 se referem a ele. Também há uma pequena atualização no modelo da Web, templates/index.html. Estas são as mudanças a serem implementadas nesta seção:

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

1. Atualizar importações

Uma importação de google.appengine.api.taskqueue traz 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 precisará lidar com carimbos de data/hora, ou seja, usar time e datetime.
  • Para registrar informações úteis sobre a execução de tarefas, precisamos de logging.

Adicionando todas essas importações, veja como o código fica antes e depois dessas mudanças:

ANTES:

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

AFTER:

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 de envio por push (reunir 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 de envio por push, com características iguais ou diferentes, consulte a documentação sobre como criar filas de envio por push.

O objetivo principal deste codelab é adicionar uma tarefa (à fila push default) que exclui visitas antigas do Datastore que não são mais exibidas. O app de referência registra cada visita (solicitação GET para /) criando uma nova entidade Visit e, em seguida, busca e mostra as visitas mais recentes. Nenhuma das visitas mais antigas será exibida ou usada novamente. Portanto, a tarefa de push exclui todas as visitas mais antigas do que a mais antiga exibida. Para 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 do último Visit, o mais antigo exibido. É seguro excluir todas as visitas mais antigas que essa.
  2. Crie uma tarefa de envio por push com esse carimbo de data/hora como payload e direcione-a ao manipulador de tarefas, acessível por um HTTP POST 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) para a tarefa, mas também registre-o (como uma string) e retorne essa string como um valor sentinela para mostrar ao usuário.

Tudo isso acontece em fetch_visits(), e esta é a aparência antes e depois de fazer essas atualizações:

ANTES:

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

AFTER:

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 um gerenciador de tarefas (código chamado quando a tarefa é executada)

Embora a exclusão de visitas antigas pudesse ser facilmente realizada no fetch_visits(), reconheça que essa funcionalidade não tem muito a ver com o usuário final. É uma funcionalidade auxiliar e uma boa opção para processamento assíncrono fora das solicitações padrão de apps. O usuário final vai se beneficiar 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 faz o seguinte:

  1. Extrai o payload de carimbo de data/hora da "visita mais antiga".
  2. Emite uma consulta do Datastore para encontrar todas as entidades mais antigas que esse carimbo de data/hora.
  3. Opta por uma consulta "somente chaves" mais rápida porque não são necessários dados reais do usuário.
  4. Registra o número de entidades a serem excluídas (incluindo zero).
  5. Chama ndb.delete_multi() para excluir entidades (ignoradas se não houver).
  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 condição do Jinja2 para mostrar 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 este 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 conclui o codelab implantando o app e verificando se ele funciona conforme o esperado e em qualquer saída refletida. Depois da validação do app, faça uma limpeza e pense nas próximas etapas.

Implantar e verificar o aplicativo

Implante o app com gcloud app deploy. A saída será idêntica ao app do módulo 1, exceto por uma nova linha na parte de baixo mostrando quais visitas serão excluídas:

4aa8a2cb5f527079.png

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

Limpar

Geral

Se você terminou por enquanto, recomendamos que desative o app do App Engine para evitar cobranças. No entanto, se você quiser testar ou experimentar mais, a plataforma do App Engine tem uma cota sem custo financeiro. Portanto, enquanto você não exceder esse nível de uso, não vai receber cobranças. Isso é para computação, mas também pode haver cobranças por serviços relevantes do App Engine. Consulte a página de preços para mais informações. Se essa migração envolver outros serviços do Cloud, eles serão cobrados separadamente. Em qualquer caso, se aplicável, consulte a seção "Específico para este codelab" abaixo.

Para total transparência, a implantação em uma plataforma de computação sem servidor do Google Cloud, como o App Engine, gera custos mínimos de build e armazenamento. O Cloud Build e o Cloud Storage têm cotas sem custo financeiro próprias. O armazenamento dessa imagem usa parte dessa cota. No entanto, talvez você more em uma região que não tem um nível sem custo financeiro. Por isso, fique de olho no uso do armazenamento para minimizar possíveis custos. As "pastas" específicas do Cloud Storage que você precisa 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 da sua PROJECT_ID e *LOC*ação. Por exemplo, "us" se o app estiver hospedado nos EUA.

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

Específico para este 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 para rastrear visitantes, resultando no app de exemplo do módulo 7. A próxima migração ensina como fazer upgrade das tarefas push do App Engine para o Cloud Tasks, se você quiser. Desde o outono de 2021, os usuários não precisam 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 próximo é o codelab do Módulo 8. Além disso, há outras migrações a serem consideradas, como Cloud Datastore, Cloud Memorystore, Cloud Storage ou Cloud Pub/Sub (filas de extração). Também há migrações entre produtos para o Cloud Run e o Cloud Functions. Todo o conteúdo da Serverless Migration Station (codelabs, vídeos, código-fonte [quando disponível]) pode ser acessado no repositório de código aberto.

7. Migração para o Python 3

No outono de 2021, a equipe do App Engine estendeu o suporte de muitos dos serviços agrupados para ambientes de execução de segunda geração (originalmente disponíveis apenas em ambientes de execução de primeira geração). Isso significa que não é mais necessário migrar de serviços agrupados, como a fila de tarefas do App Engine, para equivalentes autônomos do Cloud ou de terceiros, como o Cloud Tasks, ao fazer a portabilidade do app para o Python 3. Em outras palavras, você pode continuar usando a fila de tarefas em apps do App Engine em Python 3, desde que faça o refactoring do código para acessar serviços incluídos de ambientes de execução de próxima geração.

Saiba mais sobre como migrar o uso de serviços em pacote 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, abaixo estão vinculadas as versões em Python 3 dos apps dos módulos 1 e 7, portados para Python 3 e ainda usando o NDB do App Engine e a fila de tarefas.

8. Outros recursos

Confira abaixo mais recursos para desenvolvedores que querem saber mais sobre este ou outros módulos de migração e produtos relacionados. Isso inclui locais para enviar feedback sobre o conteúdo, links para o código e vários documentos 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 do Módulo 7 (FINISH) podem ser encontrados na tabela abaixo.

Codelab

Python 2

Python 3

Módulo 1

código

código (não abordado neste tutorial)

Módulo 7 (este codelab)

código

código (não abordado neste tutorial)

Recursos on-line

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

Filas de tarefas do App Engine

Plataforma do App Engine

Outras informações da nuvem

Vídeos

Licença

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