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.
O objetivo deste codelab é mostrar aos desenvolvedores do App Engine em Python 2 como migrar das tarefas pull da fila de tarefas do App Engine para o Cloud Pub/Sub. Há também uma migração implícita do App Engine NDB para o Cloud NDB para acesso ao Datastore (abordado principalmente no Módulo 2), além de um upgrade para o Python 3.
No módulo 18, você aprende a adicionar o uso de tarefas de pull no seu app. Neste módulo, você vai pegar o app concluído do módulo 18 e migrar esse uso para o Cloud Pub/Sub. Quem usa filas de tarefas para tarefas push vai migrar para o Cloud Tasks e precisa consultar os módulos de 7 a 9.
Você vai aprender a
- Substitua o uso da fila de tarefas do App Engine (tarefas pull) pelo Cloud Pub/Sub
- Substitua o uso do NDB do App Engine pelo NDB do Cloud (consulte também o Módulo 2).
- Portar o app para Python 3
O que é necessário
- Um projeto do Google Cloud Platform com uma conta de faturamento do GCP ativa
- Habilidades básicas em Python
- Conhecimento prático de comandos comuns do Linux
- Conhecimento básico sobre desenvolvimento e implantação de apps do App Engine
- Um app de exemplo funcional do App Engine do módulo 18
Pesquisa
Como você usará este tutorial?
Como você classificaria sua experiência com Python?
Como você classificaria sua experiência de uso dos serviços do Google Cloud?
2. Contexto
A fila de tarefas do App Engine é compatível com tarefas push e pull. Para melhorar a portabilidade do aplicativo, o Google Cloud recomenda migrar de serviços legados agrupados, como a fila de tarefas, para outros serviços autônomos do Cloud ou equivalentes de terceiros.
- Os usuários de tarefas push da fila de tarefas precisam migrar para o Cloud Tasks.
- Os usuários da fila de tarefas pull precisam migrar para o Cloud Pub/Sub.
Os módulos de migração 7 a 9 abordam a migração de tarefas de push, enquanto os módulos 18 e 19 se concentram na migração de tarefas de pull. Embora o Cloud Tasks corresponda mais de perto às tarefas push da fila de tarefas, o Pub/Sub não é tão parecido com as tarefas pull da fila de tarefas.
O Pub/Sub tem mais recursos do que a funcionalidade de extração fornecida pelo Task Queue. Por exemplo, o Pub/Sub também tem funcionalidade de push, mas o Cloud Tasks é mais parecido com as tarefas push da fila de tarefas. Portanto, o push do Pub/Sub não é abordado por nenhum dos módulos de migração. Este codelab do Módulo 19 demonstra como alternar o mecanismo de enfileiramento das filas pull da fila de tarefas para o Pub/Sub, além de migrar do App Engine NDB para o Cloud NDB para acesso ao Datastore, repetindo a migração do Módulo 2.
Embora o código do Módulo 18 seja "anunciado" como um app de exemplo do Python 2, a origem em si é compatível com Python 2 e 3, e permanece assim mesmo após a migração para o Cloud Pub/Sub (e o Cloud NDB) aqui no Módulo 19.
Este tutorial inclui as seguintes etapas:
- Configuração/Pré-trabalho
- Atualizar a configuração
- Modificar o código do aplicativo
3. Configuração/Pré-trabalho
Esta seção explica como:
- Configurar seu projeto do Cloud
- Receber app de amostra do valor de referência
- (Re)Implantar e validar o app de referência
- Ativar novos serviços/APIs do Google Cloud
Essas etapas garantem que você comece com um código funcional e que ele esteja pronto para migração para os serviços do Cloud.
1. Configurar projeto
Se você concluiu o codelab do Módulo 18, reutilize o 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 um app do App Engine ativado. Encontre o ID do projeto, porque você vai precisar dele durante este codelab. Use-o sempre que encontrar a variável PROJECT_ID.
2. Receber app de amostra do valor de referência
Um dos pré-requisitos é ter um app do App Engine do módulo 18 funcionando. Por isso, conclua o codelab (recomendado; link acima) ou copie o código do módulo 18 do repositório. Independentemente de você usar o seu ou o nosso, é aqui que vamos começar ("START"). Este codelab orienta você na migração, concluindo com um código semelhante ao que está na pasta do repositório do Módulo 19 ("FINISH").
- INICIAR: pasta do módulo 18 (Python 2)
- CONCLUIR: pasta do módulo 19 (Python 2 e 3)
- Repositório completo (para clonar ou fazer o download do arquivo ZIP)
Independente do app do Módulo 18 que você usar, a pasta vai ser parecida com a abaixo, possivelmente com uma pasta lib também:
$ ls README.md appengine_config.py queue.yaml templates app.yaml main.py requirements.txt
3. (Re)Implantar e validar o app de referência
Siga estas etapas para implantar o app do módulo 18:
- Exclua a pasta
lib, se houver uma, e executepip install -t lib -r requirements.txtpara preencherlibnovamente. Talvez seja necessário usarpip2se você tiver o Python 2 e o 3 instalados na sua máquina de desenvolvimento. - Verifique se você instalou e inicializou a ferramenta de linha de comando
gcloude se revisou o uso dela. - (Opcional) Defina seu projeto na nuvem com
gcloud config set projectPROJECT_IDse não quiser inserirPROJECT_IDcom cada comandogcloudemitido. - Implante o app de exemplo com
gcloud app deploy - Confirme se o app é executado conforme o esperado sem problemas. Se você concluiu o codelab do módulo 18, o app mostra os principais visitantes e as visitas mais recentes (ilustrado abaixo). Caso contrário, talvez não haja contagens de visitantes para mostrar.

Antes de migrar o app de exemplo do módulo 18, é necessário ativar os serviços do Google Cloud que o app modificado vai usar.
4. Ativar novos serviços/APIs do Google Cloud
O app antigo usava serviços em pacote do App Engine, que não exigem configuração adicional. No entanto, os serviços independentes do Cloud exigem, e o app atualizado vai usar o Cloud Pub/Sub e o Cloud Datastore (pela biblioteca de cliente do Cloud NDB). O App Engine e as duas APIs do Cloud têm cotas do nível "Sempre sem custo financeiro". Portanto, desde que você permaneça dentro desses limites, não haverá cobranças ao concluir este tutorial. As APIs do Cloud podem ser ativadas no console do Cloud ou na linha de comando, dependendo da sua preferência.
No Console do Cloud
Acesse a página da biblioteca do Gerenciador de APIs (para o projeto correto) no console do Cloud e pesquise as APIs Cloud Datastore e Cloud Pub/Sub usando a barra de pesquisa no meio da página:

Clique no botão Ativar para cada API separadamente. Talvez seja necessário informar dados de faturamento. Por exemplo, esta é a página da biblioteca da API Cloud Pub/Sub:

Na linha de comando
Embora seja visualmente informativo ativar APIs no console, algumas pessoas preferem a linha de comando. Emita o comando gcloud services enable pubsub.googleapis.com datastore.googleapis.com para ativar as duas APIs ao mesmo tempo:
$ gcloud services enable pubsub.googleapis.com datastore.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
Talvez seja necessário inserir informações de faturamento. Se você quiser ativar outras APIs do Cloud e saber quais são os URIs delas, acesse a parte de baixo da página da biblioteca de cada API. Por exemplo, observe pubsub.googleapis.com como o "Nome do serviço" na parte de baixo da página do Pub/Sub acima.
Depois de concluir as etapas, seu projeto poderá acessar as APIs. Agora é hora de atualizar o aplicativo para usar essas APIs.
4. Crie recursos do Pub/Sub
Resumindo a ordem da sequência do fluxo de trabalho da fila de tarefas do módulo 18:
- O módulo 18 usou o arquivo
queue.yamlpara criar uma fila pull chamadapullq. - O app adiciona tarefas à fila pull para rastrear visitantes.
- As tarefas são processadas por um worker, alocado por um período limitado (uma hora).
- As tarefas são executadas para contabilizar as contagens de visitantes recentes.
- As tarefas são excluídas da fila após a conclusão.
Você vai replicar um fluxo de trabalho semelhante com o Pub/Sub. A próxima seção apresenta a terminologia básica do Pub/Sub, com três maneiras diferentes de criar os recursos necessários do Pub/Sub.
Terminologia da fila de tarefas do App Engine (pull) x Cloud Pub/Sub
A mudança para o Pub/Sub exige um pequeno ajuste no seu vocabulário. Confira abaixo as principais categorias e os termos relevantes dos dois produtos. Consulte também o guia de migração, que apresenta comparações semelhantes.
- Estrutura de dados de enfileiramento:com a fila de tarefas, os dados vão para filas pull; com o Pub/Sub, os dados vão para tópicos.
- Unidades de dados enfileirados : as tarefas de extração com a fila de tarefas são chamadas de mensagens com o Pub/Sub.
- Processadores de dados:com a fila de tarefas, os workers acessam tarefas de extração. Com o Pub/Sub, você precisa de assinaturas/assinantes para receber mensagens.
- Extração de dados : alugar uma tarefa pull é o mesmo que extrair uma mensagem de um tópico (por uma assinatura).
- Limpeza/conclusão : excluir uma tarefa da fila de tarefas de uma fila pull quando você terminar é análogo a confirmar uma mensagem do Pub/Sub.
Embora o produto de enfileiramento mude, o fluxo de trabalho permanece relativamente semelhante:
- Em vez de uma fila pull, o app usa um tópico chamado
pullq. - Em vez de adicionar tarefas a uma fila pull, o app envia mensagens a um tópico (
pullq). - Em vez de um worker alugar tarefas da fila pull, um assinante chamado
workerextrai mensagens do tópicopullq. - O app processa payloads de mensagens, incrementando as contagens de visitantes no Datastore.
- Em vez de excluir tarefas da fila pull, o app confirma as mensagens processadas.
Com a fila de tarefas, a configuração envolve a criação da fila pull. Com o Pub/Sub, a configuração exige a criação de um tópico e uma assinatura. No módulo 18, processamos queue.yaml fora da execução do app. Agora, o mesmo precisa ser feito com o Pub/Sub.
Há três opções para criar tópicos e assinaturas:
- No console do Cloud
- Na linha de comando ou
- Por código (script Python curto)
Escolha uma das opções abaixo e siga as instruções correspondentes para criar seus recursos do Pub/Sub.
No console do Cloud
Para criar um tópico no Console do Cloud, siga estas etapas:
- Acesse a página de tópicos do Pub/Sub no Console do Cloud.
- Clique em Criar tópico na parte de cima. Uma nova janela de diálogo será aberta (veja a imagem abaixo).
- No campo ID do tópico, insira
pullq. - Desmarque todas as opções marcadas e selecione Chave de criptografia gerenciada pelo Google.
- Clique no botão Criar tópico.
Esta é a aparência da caixa de diálogo de criação de tópico:

Agora que você tem um tópico, é necessário criar uma assinatura para ele:
- Acesse a página de assinaturas do Pub/Sub no console do Cloud.
- Clique em Criar assinatura na parte de cima (veja a imagem abaixo).
- Insira
workerno campo ID da assinatura. - Escolha
pullqno menu suspenso Selecionar um tópico do Cloud Pub/Sub, observando o "nome do caminho totalmente qualificado", por exemplo,projects/PROJECT_ID/topics/pullq. - Em Tipo de entrega, selecione Pull.
- Deixe as outras opções como estão e clique no botão Criar.
Esta é a aparência da tela de criação de assinatura:

Você também pode criar uma assinatura na página Tópicos. Esse "atalho" pode ser útil para associar tópicos a assinaturas. Para saber mais sobre como criar assinaturas, consulte a documentação.
Na linha de comando
Os usuários do Pub/Sub podem criar tópicos e assinaturas com os comandos gcloud pubsub topics create TOPIC_ID e gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID, respectivamente. A execução desses comandos com um TOPIC_ID de pullq e um SUBSCRIPTION_ID de worker resulta na seguinte saída para o projeto PROJECT_ID:
$ gcloud pubsub topics create pullq Created topic [projects/PROJECT_ID/topics/pullq]. $ gcloud pubsub subscriptions create worker --topic=pullq Created subscription [projects/PROJECT_ID/subscriptions/worker].
Consulte também esta página na documentação do guia de início rápido. Usar a linha de comando pode simplificar fluxos de trabalho em que tópicos e assinaturas são criados regularmente. Esses comandos podem ser usados em scripts shell para essa finalidade.
Por código (script Python curto)
Outra maneira de automatizar a criação de tópicos e assinaturas é usando a API Pub/Sub no código-fonte. Confira abaixo o código do script maker.py na pasta do repositório do módulo 19.
from __future__ import print_function
import google.auth
from google.api_core import exceptions
from google.cloud import pubsub
_, PROJECT_ID = google.auth.default()
TOPIC = 'pullq'
SBSCR = 'worker'
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
def make_top():
try:
top = ppc_client.create_topic(name=TOP_PATH)
print('Created topic %r (%s)' % (TOPIC, top.name))
except exceptions.AlreadyExists:
print('Topic %r already exists at %r' % (TOPIC, TOP_PATH))
def make_sub():
try:
sub = psc_client.create_subscription(name=SUB_PATH, topic=TOP_PATH)
print('Subscription created %r (%s)' % (SBSCR, sub.name))
except exceptions.AlreadyExists:
print('Subscription %r already exists at %r' % (SBSCR, SUB_PATH))
try:
psc_client.close()
except AttributeError: # special Py2 handler for grpcio<1.12.0
pass
make_top()
make_sub()
A execução desse script resulta na saída esperada (desde que não haja erros):
$ python3 maker.py Created topic 'pullq' (projects/PROJECT_ID/topics/pullq) Subscription created 'worker' (projects/PROJECT_ID/subscriptions/worker)
Chamar a API para criar recursos já existentes resulta em uma exceção google.api_core.exceptions.AlreadyExists gerada pela biblioteca de cliente, processada normalmente pelo script:
$ python3 maker.py Topic 'pullq' already exists at 'projects/PROJECT_ID/topics/pullq' Subscription 'worker' already exists at 'projects/PROJECT_ID/subscriptions/worker'
Se você não conhece o Pub/Sub, consulte o white paper sobre a arquitetura do Pub/Sub para mais informações.
5. Atualizar a configuração
As atualizações na configuração incluem a mudança de vários arquivos de configuração e a criação do equivalente a filas pull do App Engine, mas no ecossistema do Cloud Pub/Sub.
Excluir queue.yaml
Estamos abandonando completamente a fila de tarefas. Portanto, exclua queue.yaml porque o Pub/Sub não usa esse arquivo. Em vez de criar uma fila pull, você vai criar um tópico (e uma assinatura) do Pub/Sub.
requirements.txt
Adicione google-cloud-ndb e google-cloud-pubsub a requirements.txt para unir flask do módulo 18. O requirements.txt atualizado do módulo 19 vai ficar assim:
flask
google-cloud-ndb
google-cloud-pubsub
Esse arquivo requirements.txt não tem números de versão, o que significa que as versões mais recentes estão selecionadas. Se houver incompatibilidades, siga a prática padrão de usar números de versão para bloquear versões funcionais de um app.
app.yaml
As mudanças em app.yaml variam dependendo se você vai continuar usando o Python 2 ou fazer upgrade para o Python 3.
Python 2
A atualização acima para requirements.txt adiciona o uso das bibliotecas de cliente do Google Cloud. Elas exigem suporte adicional do App Engine, ou seja, algumas bibliotecas integradas, setuptools e grpcio. O uso de bibliotecas integradas exige uma seção libraries em app.yaml e números de versão da biblioteca ou "latest" para a versão mais recente disponível nos servidores do App Engine. O módulo 18 app.yaml ainda não tem uma dessas seções:
ANTES:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
Adicione uma seção libraries a app.yaml com entradas para setuptools e grpcio, selecionando as versões mais recentes. Adicione também uma entrada de marcador de posição runtime para Python 3, comentada junto com uma versão 3.x atual, por exemplo, 3.10, no momento da redação deste artigo. Com essas mudanças, o app.yaml agora fica assim:
AFTER:
#runtime: python310
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: setuptools
version: latest
- name: grpcio
version: latest
Python 3
Para usuários do Python 3 e do app.yaml, o foco é remover coisas. Nesta seção, você vai excluir a seção handlers, as diretivas threadsafe e api_version e não vai criar uma seção libraries.
Os ambientes de execução de segunda geração não fornecem bibliotecas integradas de terceiros. Portanto, uma seção libraries não é necessária em app.yaml. Além disso, não é mais necessário copiar (às vezes conhecido como disponibilização de pacotes de terceiros ou autoagrupamento) pacotes de terceiros não integrados. Você só precisa listar as bibliotecas de terceiros que seu app usa em requirements.txt.
A seção handlers em app.yaml é para especificar gerenciadores de aplicativos (scripts) e arquivos estáticos. Como o ambiente de execução do Python 3 exige que as bibliotecas da Web façam o próprio roteamento, todos os gerenciadores de script precisam ser alterados para auto. Se o app (como o do módulo 18) não veicular arquivos estáticos, todas as rotas serão auto, o que as torna irrelevantes. Como resultado, a seção handlers também não é necessária. Exclua-a.
Por fim, como as diretivas threadsafe e api_version não são usadas no Python 3, exclua-as também. O resultado é que você precisa excluir todas as seções de app.yaml para que apenas a diretiva runtime permaneça, especificando uma versão moderna do Python 3, por exemplo, 3.10. Veja como o app.yaml fica antes e depois dessas atualizações:
ANTES:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
AFTER:
runtime: python310
Para quem não está pronto para excluir tudo do app.yaml para Python 3, disponibilizamos um arquivo alternativo app3.yaml na pasta do repositório do módulo 19. Se você quiser usar esse arquivo para implantações, adicione o nome dele ao final do comando: gcloud app deploy app3.yaml. Caso contrário, o padrão será usar e implantar o app com o arquivo app.yaml do Python 2 que você deixou inalterado.
appengine_config.py
Se você estiver fazendo upgrade para o Python 3, não será necessário usar appengine_config.py. Portanto, exclua-o. Não é necessário porque o suporte a bibliotecas de terceiros só exige que elas sejam especificadas em requirements.txt. Usuários do Python 2, continuem lendo.
O appengine_config.py do módulo 18 tem o código adequado para oferecer suporte a bibliotecas de terceiros, por exemplo, Flask e as bibliotecas de cliente do Cloud que acabaram de ser adicionadas a requirements.txt:
ANTES:
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
No entanto, esse código sozinho não é suficiente para oferecer suporte às bibliotecas integradas recém-adicionadas (setuptools, grpcio). Algumas linhas a mais são necessárias. Portanto, atualize appengine_config.py para que fique assim:
AFTER:
import pkg_resources
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)
Mais detalhes sobre as mudanças necessárias para oferecer suporte às bibliotecas de cliente do Cloud podem ser encontrados na documentação de migração de serviços agrupados.
Outras atualizações de configuração
Se você tiver uma pasta lib, exclua-a. Se você usa o Python 2, reabasteça a pasta lib emitindo o seguinte comando:
pip install -t lib -r requirements.txt # or pip2
Se você tiver o Python 2 e o 3 instalados no sistema de desenvolvimento, talvez seja necessário usar pip2 em vez de pip.
6. Modificar o código do aplicativo
Esta seção apresenta atualizações no arquivo principal do aplicativo, main.py, substituindo o uso de filas de extração da fila de tarefas do App Engine pelo Cloud Pub/Sub. Não há mudanças no modelo da Web, templates/index.html. Os dois apps devem operar de forma idêntica, mostrando os mesmos dados.
Atualizar importações e inicialização
Há várias atualizações nas importações e na inicialização:
- Para as importações, substitua o App Engine NDB e a fila de tarefas pelo Cloud NDB e o Pub/Sub.
- Renomeie
pullqde um nomeQUEUEpara um nomeTOPIC. - Com as tarefas de extração, o worker as alugava por uma hora, mas com o Pub/Sub, os tempos limite são medidos por mensagem. Portanto, exclua a constante
HOUR. - As APIs do Cloud exigem o uso de um cliente de API. Portanto, inicie aqueles para o Cloud NDB e o Cloud Pub/Sub. Este último fornece clientes para tópicos e assinaturas.
- O Pub/Sub exige o ID do projeto na nuvem. Portanto, importe e receba-o de
google.auth.default(). - O Pub/Sub exige "nomes de caminhos totalmente qualificados" para tópicos e assinaturas. Portanto, crie-os usando as funções de conveniência
*_path().
A seguir, estão as importações e a inicialização do módulo 18, seguidas de como as seções devem ficar após a implementação das mudanças acima. A maior parte do novo código são vários recursos do Pub/Sub:
ANTES:
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__)
AFTER:
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, pubsub
LIMIT = 10
TASKS = 1000
TOPIC = 'pullq'
SBSCR = 'worker'
app = Flask(__name__)
ds_client = ndb.Client()
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
_, PROJECT_ID = google.auth.default()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
Acessar atualizações do modelo de dados
O modelo de dados Visit não muda. O acesso ao Datastore exige o uso explícito do gerenciador de contexto do cliente da API Cloud NDB, ds_client.context(). No código, isso significa encapsular as chamadas do Datastore em store_visit() e fetch_visits() dentro de blocos with do Python. Essa atualização é idêntica ao que foi abordado no módulo 2.
A mudança mais relevante para o Pub/Sub é substituir o enfileiramento de uma tarefa de extração da fila de tarefas pela publicação de uma mensagem do Pub/Sub no tópico pullq. Confira abaixo o código antes e depois dessas atualizações:
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 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)
AFTER:
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'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
ppc_client.publish(TOP_PATH, remote_addr.encode('utf-8'))
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
Atualizações do modelo de dados VisitorCount
O modelo de dados VisitorCount não muda e fetch_counts(), exceto por encapsular a consulta do Datastore em um bloco with, conforme ilustrado abaixo:
ANTES:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
AFTER:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
with ds_client.context():
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
Atualizar o código do worker
O código do worker é atualizado para substituir o NDB pelo Cloud NDB e a fila de tarefas pelo Pub/Sub, mas o fluxo de trabalho permanece o mesmo.
- Encapsule as chamadas do Datastore no bloco do gerenciador de contexto do Cloud NDB
with. - A limpeza da fila de tarefas envolve a exclusão de todas as tarefas da fila pull. Com o Pub/Sub, os "IDs de confirmação" são coletados em
ackse depois excluídos/confirmados no final. - As tarefas pull da fila de tarefas são alugadas de maneira semelhante às mensagens pull do Pub/Sub. Enquanto as tarefas de extração são excluídas com os próprios objetos de tarefa, as mensagens do Pub/Sub são excluídas com os IDs de confirmação.
- Os payloads de mensagens do Pub/Sub exigem bytes (não strings Python). Portanto, há codificação e decodificação UTF-8 ao publicar e extrair mensagens de um tópico, respectivamente.
Substitua log_visitors() pelo código atualizado abaixo, implementando as mudanças descritas acima:
ANTES:
@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))
AFTER:
@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 = {}
acks = set()
rsp = psc_client.pull(subscription=SUB_PATH, max_messages=TASKS)
msgs = rsp.received_messages
for rcvd_msg in msgs:
acks.add(rcvd_msg.ack_id)
visitor = rcvd_msg.message.data.decode('utf-8')
tallies[visitor] = tallies.get(visitor, 0) + 1
if acks:
psc_client.acknowledge(subscription=SUB_PATH, ack_ids=acks)
try:
psc_client.close()
except AttributeError: # special handler for grpcio<1.12.0
pass
# increment those counts in Datastore and return
if tallies:
with ds_client.context():
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(msgs), len(tallies))
Não há mudanças no gerenciador principal do aplicativo root(). Nenhuma mudança é necessária no arquivo de modelo HTML, templates/index.html, o que conclui todas as atualizações necessárias. Parabéns por chegar ao novo aplicativo do módulo 19 usando o Cloud Pub/Sub!
7. Resumo/limpeza
Implante o app para verificar se ele funciona conforme o esperado e em qualquer saída refletida. Execute também o worker para processar as contagens de visitantes. Depois da validação do app, faça as etapas de limpeza e considere as próximas etapas.
Implantar e verificar o aplicativo
Verifique se você já criou o tópico pullq e a assinatura worker. Se isso já foi feito e o app de exemplo está pronto, implante o app com gcloud app deploy. A saída deve ser idêntica ao app do módulo 18, exceto que você substituiu todo o mecanismo de enfileiramento subjacente:

O front-end da Web do app agora verifica se essa parte do aplicativo funciona. Embora essa parte do app consulte e mostre os principais visitantes e as visitas mais recentes, lembre-se de que o app registra essa visita e cria uma tarefa de extração para adicionar o visitante à contagem geral. Essa tarefa agora está na fila aguardando processamento.
É possível executar isso com um serviço de back-end do App Engine, um job cron, navegando até /log ou emitindo uma solicitação HTTP de linha de comando. Confira um exemplo de execução e saída da chamada do código do worker com curl (substitua seu 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!
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/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- Os links de armazenamento acima dependem da sua
PROJECT_IDe *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:
- Diferentes componentes do Cloud Pub/Sub têm um nível sem custo financeiro. Determine seu uso geral para ter uma ideia melhor das implicações de custo e consulte a página de preços para mais detalhes.
- O serviço App Engine Datastore é fornecido pelo Cloud Datastore (Cloud Firestore no modo Datastore), que também tem um nível sem custo financeiro. Consulte a página de preços para mais informações.
Próximas etapas
Além deste tutorial, outros módulos de migração que se concentram em migrar dos serviços agrupados legados incluem:
- Módulo 2: migrar do App Engine
ndbpara o Cloud NDB - Módulos 7 a 9: migrar da fila de tarefas do App Engine (tarefas push) para o Cloud Tasks
- Módulos 12 e 13: migrar do Memcache do App Engine para o Cloud Memorystore
- Módulos 15 e 16: migrar do Blobstore do App Engine para o Cloud Storage
O App Engine não é mais a única plataforma sem servidor no Google Cloud. Se você tem um app pequeno do App Engine ou um com funcionalidade limitada e quer transformá-lo em um microsserviço independente, ou se quer dividir um app monolítico em vários componentes reutilizáveis, esses são bons motivos para considerar a migração para o Cloud Functions. Se a contêinerização se tornou parte do seu fluxo de trabalho de desenvolvimento de aplicativos, principalmente se ele consistir em um pipeline de CI/CD (integração contínua/entrega ou implantação contínua), considere migrar para o Cloud Run. Esses cenários são abordados nos seguintes módulos:
- Migrar do App Engine para o Cloud Functions: consulte o Módulo 11
- Migrar do App Engine para o Cloud Run: consulte o Módulo 4 para contentorizar seu app com o Docker ou o Módulo 5 para fazer isso sem contêineres, conhecimento do Docker ou
Dockerfiles
A mudança para outra plataforma sem servidor é opcional. Recomendamos considerar as melhores opções para seus apps e casos de uso antes de fazer qualquer mudança.
Independente do módulo de migração que você considerar em seguida, 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. O README do repositório também oferece orientações sobre quais migrações considerar e a "ordem" relevante dos módulos de migração.
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 dos codelabs
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 18 (START) e do Módulo 19 (FINISH) podem ser encontrados na tabela abaixo.
Codelab | Python 2 | Python 3 |
(n/a) | ||
Módulo 19 (este codelab) | (igual ao Python 2, mas use app3.yaml, a menos que você tenha atualizado app.yaml conforme explicado acima) |
Referências on-line
Confira abaixo os recursos relevantes para este tutorial:
Filas de tarefas do App Engine
- Visão geral da fila de tarefas do App Engine
- Visão geral das filas de extração da fila de tarefas do App Engine
- App de exemplo completo da fila pull da fila de tarefas do App Engine
- Como criar filas pull da fila de tarefas
- Vídeo de lançamento da fila pull do Google I/O 2011 ( app de exemplo Votelator)
- Referência
queue.yaml queue.yamlx Cloud Tasks- Guia de migração de filas pull para o Pub/Sub
Cloud Pub/Sub
- Página do produto Cloud Pub/Sub
- Como usar bibliotecas de cliente do Pub/Sub
- Exemplos da biblioteca de cliente Python do Pub/Sub
- Documentação da biblioteca de cliente Python do Pub/Sub
- Criar e gerenciar tópicos do Pub/Sub
- Diretrizes para nomeação de tópicos do Pub/Sub
- Criar e gerenciar assinaturas do Pub/Sub
- App de exemplo do App Engine (flexível) (também pode ser implantado no ambiente padrão; Python 3)
- Repositório do app de exemplo acima
- Assinaturas de pull do Pub/Sub
- Assinaturas de envio por push do Pub/Sub
- App de exemplo de push do Pub/Sub do App Engine (Python 3)
- Repositório do app de exemplo de push do Pub/Sub do App Engine
- Informações sobre preços do Pub/Sub
- Cloud Tasks ou Cloud Pub/Sub? (push x pull)
NDB do App Engine e NDB do Cloud (Datastore)
- Documentação do App Engine NDB
- Repositório NDB do App Engine
- Documentos do Google Cloud NDB
- Repositório do Google Cloud NDB
- Informações de preços do Cloud Datastore
Plataforma do App Engine
- Documentação do App Engine
- Tempo de execução do Python 2 no App Engine (ambiente padrão)
- Como usar bibliotecas integradas do App Engine no App Engine do Python 2
- Tempo de execução do Python 3 no App Engine (ambiente padrão)
- Diferenças entre os ambientes de execução do Python 2 e 3 no App Engine (ambiente padrão)
- Guia de migração do App Engine (ambiente padrão) do Python 2 para o 3
- Informações sobre preços e cotas do App Engine
- Lançamento da plataforma App Engine de segunda geração (2018)
- Comparação entre plataformas de primeira e segunda geração
- Suporte de longo prazo para ambientes de execução legados
- Exemplos de migração de documentação
- Exemplos de migração gerados pela comunidade
Outras informações da nuvem
- Python no Google Cloud Platform
- Bibliotecas de cliente do Python para Google Cloud
- Nível "Sempre sem custo financeiro" do Google Cloud
- SDK do Google Cloud (ferramenta de linha de comando
gcloud) - Toda a documentação do Google Cloud
Vídeos
- Serverless Migration Station (em inglês)
- Expedições sem servidor
- Inscreva-se no Google Cloud Tech
- Inscreva-se no Google Developers
Licença
Este conteúdo está sob a licença Atribuição 2.0 Genérica da Creative Commons.