Como usar a fila de tarefas do App Engine (tarefas pull) em apps Flask (módulo 18)

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 incluir e usar tarefas de pull da fila de tarefas do App Engine no app de exemplo do codelab do módulo 1. Neste tutorial do Módulo 18, adicionamos o uso de tarefas pull e as migramos para o Cloud Pub/Sub no módulo 19. Aqueles que usam filas de tarefas para tarefas push migrarão para o Cloud Tasks e devem consultar os Módulos 7-9.

Você vai aprender a

  • Usar o serviço pacote/API Task Queue do App Engine
  • Adicionar o uso da fila pull a um app Python 2 básico do App Engine NoSQL

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

Para migrar das tarefas pull 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. O app de exemplo mostra as visitas mais recentes ao usuário final. Tudo bem, mas é mais interessante também acompanhar os visitantes para saber quem mais visita eles.

Embora seja possível usar tarefas push para essas contagens de visitantes, queremos dividir a responsabilidade entre o aplicativo de amostra, que tem a função de registrar visitas e responder imediatamente aos usuários, e um "worker" designado. cujo trabalho é calcular as contagens de visitantes fora do fluxo de trabalho normal de solicitação/resposta.

Para implementar esse design, estamos adicionando o uso de filas pull ao aplicativo principal, além de oferecermos suporte à funcionalidade do worker. O worker pode ser executado como um processo separado (como uma instância de back-end ou um código em execução em uma VM que está sempre ativa), um cron job ou uma solicitação HTTP de linha de comando básica usando curl ou wget. Após essa integração, será possível migrar o app para o Cloud Pub/Sub no próximo codelab (módulo 19).

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, reutilize 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 um aplicativo do App Engine ativado. Encontre o ID do projeto, porque você vai precisar dele várias vezes neste codelab e use-o sempre que encontrar a variável PROJECT_ID.

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

Um dos pré-requisitos deste 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. 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 18.

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

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

3. (Re) Implantar aplicativo de referência

Execute as etapas a seguir para implantar o app 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 e mostra as visitas mais recentes (ilustradas 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). Em vez disso, adicione um novo arquivo de configuração, queue.yaml, com o conteúdo abaixo, colocando-o no mesmo diretório de nível superior:

queue:
- name: pullq
  mode: pull

O arquivo queue.yaml especifica todas as filas de tarefas que existem para seu aplicativo (exceto a fila [push] default, que é criada automaticamente pelo App Engine. Nesse caso, há apenas uma: uma fila pull chamada pullq. O App Engine exige que a diretiva mode seja especificada como pull. Caso contrário, ele cria uma fila push por padrão. Saiba mais sobre como criar filas pull na documentação. Consulte também a página de referência do queue.yaml para outras opções.

Implante esse arquivo separadamente do app. Você ainda usará gcloud app deploy, mas também fornecerá queue.yaml na linha de comando:

$ gcloud app deploy queue.yaml
Configurations to update:

descriptor:      [/tmp/mod18-gaepull/queue.yaml]
type:            [task queues]
target project:  [my-project]

WARNING: Caution: You are updating queue configuration. This will override any changes performed using 'gcloud tasks'. More details at
https://cloud.google.com/tasks/docs/queue-yaml

Do you want to continue (Y/n)?

Updating config [queue]...⠹WARNING: We are using the App Engine app location (us-central1) as the default location. Please use the "--location" flag if you want to use a different location.
Updating config [queue]...done.

Task queues have been updated.

Visit the Cloud Platform Console Task Queues page to view your queues and cron jobs.
$

5. Modificar o código do aplicativo

Esta seção apresenta atualizações para os seguintes arquivos:

  • main.py: adicione o uso de filas pull ao aplicativo principal
  • templates/index.html: atualize o modelo da Web para exibir os novos dados.

Importações e constantes

O primeiro passo é adicionar uma nova importação e várias constantes para dar suporte a filas pull:

  • Adicione uma importação da biblioteca de fila de tarefas, google.appengine.api.taskqueue.
  • Adicione três constantes para aceitar a alocação do número máximo de tarefas pull (TASKS) por uma hora (HOUR) da nossa fila pull (QUEUE).
  • Adicione uma constante para exibir as visitas mais recentes e os principais visitantes (LIMIT).

Confira abaixo o código original e a aparência dele depois das atualizações:

ANTES:

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

app = Flask(__name__)

DEPOIS:

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

HOUR = 3600
LIMIT = 10
TASKS = 1000
QNAME = 'pullq'
QUEUE = taskqueue.Queue(QNAME)
app = Flask(__name__)

Adicionar uma tarefa pull (reunir dados para a tarefa e criar tarefa na fila pull)

O modelo de dados Visit permanece o mesmo, assim como a consulta de visitas a ser exibida em fetch_visits(). A única mudança necessária nesta parte do código está em store_visit(). Além de registrar a visita, adicione uma tarefa à fila pull com o endereço IP do visitante para que o worker possa incrementar o contador de visitantes.

ANTES:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

DEPOIS:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit in Datastore and queue request to bump visitor count'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
    QUEUE.add(taskqueue.Task(payload=remote_addr, method='PULL'))

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

Criar modelo de dados e função de consulta para rastreamento de visitantes

Adicionar um modelo de dados VisitorCount para rastrear visitantes. ele precisa ter campos para o próprio visitor, bem como um counter inteiro para acompanhar o número de visitas. Em seguida, adicione uma nova função (como alternativa, pode ser um Python classmethod) chamada fetch_counts() para consultar e retornar os principais visitantes na ordem do maior para o menor. Adicione a classe e a função logo abaixo do corpo de fetch_visits():

class VisitorCount(ndb.Model):
    visitor = ndb.StringProperty(repeated=False, required=True)
    counter = ndb.IntegerProperty()

def fetch_counts(limit):
    'get top visitors'
    return VisitCount.query().order(-VisitCount.counter).fetch(limit)

Adicionar código do worker

Adicione uma nova função log_visitors() para registrar os visitantes com uma solicitação GET para /log. Ela usa um dicionário/hash para acompanhar as contagens de visitantes mais recentes, concedendo o máximo de tarefas possível por uma hora. Para cada tarefa, ele conta todas as visitas do mesmo visitante. Com as contagens em mãos, o app atualiza todas as entidades VisitorCount correspondentes que já estão no Datastore ou cria novas, se necessário. A última etapa retorna uma mensagem de texto simples indicando quantos visitantes se registraram em relação ao número de tarefas processadas. Adicione essa função a main.py logo abaixo de fetch_counts():

@app.route('/log')
def log_visitors():
    'worker processes recent visitor counts and updates them in Datastore'
    # tally recent visitor counts from queue then delete those tasks
    tallies = {}
    tasks = QUEUE.lease_tasks(HOUR, TASKS)
    for task in tasks:
        visitor = task.payload
        tallies[visitor] = tallies.get(visitor, 0) + 1
    if tasks:
        QUEUE.delete_tasks(tasks)

    # increment those counts in Datastore and return
    for visitor in tallies:
        counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
        if not counter:
            counter = VisitorCount(visitor=visitor, counter=0)
            counter.put()
        counter.counter += tallies[visitor]
        counter.put()
    return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
            len(tasks), len(tallies))

Atualizar o gerenciador principal com novos dados de exibição

Para mostrar os principais visitantes, atualize o gerenciador principal root() para invocar fetch_counts(). Além disso, o modelo será atualizado para mostrar o número de visitantes principais e as visitas mais recentes. Agrupe as contagens de visitantes com as visitas mais recentes da chamada para fetch_visits() e solte-as em um único context para transmitir ao modelo da Web. Veja abaixo o código antes e depois da mudança:

ANTES:

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

DEPOIS:

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    context = {
        'limit':  LIMIT,
        'visits': fetch_visits(LIMIT),
        'counts': fetch_counts(LIMIT),
    }
    return render_template('index.html', **context)

Estas são todas as mudanças necessárias do main.py. Confira uma representação pictórica dessas atualizações para ilustrar melhor o que você está fazendo no main.py:

ad5fd3345efc13d0.png

Atualizar o modelo da Web com novos dados de exibição

O modelo da Web templates/index.html requer uma atualização para mostrar os principais visitantes, além do payload normal dos visitantes mais recentes. Coloque os principais visitantes e suas contagens em uma tabela na parte superior da página e continue a renderizar as visitas mais recentes como antes. A única outra mudança é especificar o número mostrado pela variável limit em vez de fixar o número no código. Estas são as atualizações que você deve fazer no seu modelo da Web:

ANTES:

<!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>

DEPOIS:

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

<h1>VisitMe example</h1>

<h3>Top {{ limit }} visitors</h3>
<table border=1 cellspacing=0 cellpadding=2>
    <tr><th>Visitor</th><th>Visits</th></tr>
{% for count in counts %}
    <tr><td>{{ count.visitor|e }}</td><td align="center">{{ count.counter }}</td></tr>
{% endfor %}
</table>

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

Isso conclui as mudanças necessárias, adicionando o uso de tarefas pull da Fila de tarefas do App Engine ao aplicativo de exemplo do Módulo 1. O diretório agora representa o app de exemplo do Módulo 18 e precisa conter estes arquivos:

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

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. Execute o worker separadamente para processar as contagens de visitantes. Após a validação do app, execute as etapas de limpeza e considere as próximas etapas.

Implante e verifique o aplicativo

Verifique se você já configurou a fila pull, como fizemos no início deste codelab com gcloud app deploy queue.yaml. Se isso tiver sido concluído e o app de exemplo estiver pronto, implante o app com gcloud app deploy. A saída será idêntica ao app do Módulo 1, mas agora apresenta a opção "Principais visitantes". na parte superior:

b667551dcbab1a09.png

Embora o front-end da Web atualizado mostre os principais visitantes e as visitas mais recentes, observe que as contagens de visitantes não incluem essa visita. O aplicativo exibe as contagens anteriores de visitantes enquanto descarta uma nova tarefa, o que incrementa a contagem desse visitante na fila pull, uma tarefa que está aguardando para ser processada.

É possível executar a tarefa chamando /log de várias maneiras:

Por exemplo, se você usar curl para enviar uma solicitação GET para /log, a saída será semelhante a esta, considerando que você forneceu PROJECT_ID:

$ curl https://PROJECT_ID.appspot.com/log
DONE (with 1 task[s] logging 1 visitor[s])

A contagem atualizada será refletida na próxima visita ao site. Pronto!

Parabéns por concluir este codelab por adicionar o uso do serviço de fila pull da fila de tarefas do App Engine ao app de exemplo. Agora ele está pronto para migrar para o Cloud Pub/Sub, o Cloud NBS e o Python 3 no módulo 19.

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 para o rastreamento de visitantes e implementando o app de exemplo do Módulo 18. Na próxima migração, você vai fazer upgrade das tarefas pull do App Engine para o Cloud Pub/Sub. Desde o final de 2021, os usuários não precisam mais migrar para o Cloud Pub/Sub ao fazer upgrade para o Python 3. Leia mais sobre isso na próxima seção.

Para migrar para o Cloud Pub/Sub, consulte o codelab do Módulo 19. Além disso, há outras migrações a serem consideradas, como Cloud Datastore, Cloud Memorystore, Cloud Storage ou Cloud Tasks (filas push). 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 em pacote para ambientes de execução de 2a geração (que têm um ambiente de execução de 1a geração). Como resultado, não é mais necessário migrar de serviços agrupados, como a fila de tarefas do App Engine, para o Cloud independente ou serviços de terceiros, como o Cloud Pub/Sub, 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 18, os links abaixo estão versões do aplicativo do Módulo 1 em Python 3 transferidas para Python 3 e ainda usando o App Engine depois. Em algum momento, uma versão Python 3 do app Módulo 18 também será disponibilizada.

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 1 (INÍCIO) e do Módulo 18 (FINISH) podem ser encontrados na tabela abaixo. Eles também podem ser acessados no repositório para todas as migrações de codelab do App Engine. cloná-lo ou fazer o download de um arquivo ZIP.

Codelab

Python 2

Python 3

Módulo 1

código

code (não apresentado neste tutorial)

Módulo 18 (este codelab)

código

N/A

Referências on-line

Confira abaixo os recursos relevantes para este tutorial:

Filas de tarefas do App Engine

Plataforma do App Engine

Documentação do App Engine

Ambiente de execução do App Engine para Python 2 (ambiente padrão)

Ambiente de execução do App Engine para Python 3 (ambiente padrão)

Diferenças entre o Python 2 e o Três ambientes de execução do App Engine (ambiente padrão)

Guia de migração do App Engine (ambiente padrão) Python 2 para 3

Informações de preços e cotas do App Engine

Lançamento da plataforma App Engine de segunda geração (2018)

Suporte de longo prazo para ambientes de execução legados

Amostras de migração de documentação (em inglês)

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.