Esegui la migrazione dalle attività pull della coda di attività di App Engine a Cloud Pub/Sub (modulo 19)

1. Panoramica

La serie di codelab Serverless Migration Station (esercitazioni pratiche e autonome) e i video correlati hanno lo scopo di aiutare gli sviluppatori serverless di Google Cloud a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo, le tue app sono più portatili e hai più opzioni e flessibilità, il che ti consente di integrarti e accedere a una gamma più ampia di prodotti cloud e di eseguire più facilmente l'upgrade alle versioni più recenti del linguaggio. Sebbene inizialmente si concentri sui primi utenti di Cloud, principalmente gli sviluppatori di App Engine (ambiente standard), questa serie è abbastanza ampia da includere altre piattaforme serverless come Cloud Functions e Cloud Run o altrove, se applicabile.

Lo scopo di questo codelab è mostrare agli sviluppatori di App Engine Python 2 come eseguire la migrazione dalle attività pull della coda di attività di App Engine a Cloud Pub/Sub. Esiste anche una migrazione implicita da App Engine NDB a Cloud NDB per l'accesso a Datastore (principalmente trattata nel modulo 2), nonché un upgrade a Python 3.

Nel modulo 18, imparerai ad aggiungere l'utilizzo delle attività di pull nella tua app. In questo modulo, prenderai l'app del modulo 18 completata e ne eseguirai la migrazione a Cloud Pub/Sub. Gli utenti che utilizzano le code di attività per le attività push eseguiranno invece la migrazione a Cloud Tasks e dovranno fare riferimento ai moduli 7-9.

Imparerai a utilizzare

Che cosa ti serve

Sondaggio

Come utilizzerai questo tutorial?

Solo lettura Lettura e completamento degli esercizi

Come valuteresti la tua esperienza con Python?

Principiante Intermedio Avanzato

Come valuti la tua esperienza di utilizzo dei servizi Google Cloud?

Principiante Intermedio Avanzato

2. Sfondo

App Engine Task Queue supporta le attività push e pull. Per migliorare la portabilità delle applicazioni, Google Cloud consiglia di eseguire la migrazione dai servizi integrati legacy come Task Queue ad altri servizi autonomi di Cloud o equivalenti di terze parti.

I moduli 7-9 trattano la migrazione delle attività push, mentre i moduli 18-19 si concentrano sulla migrazione delle attività pull. Anche se Cloud Tasks corrisponde più da vicino alle attività push di Task Queues, Pub/Sub non è un analogo altrettanto vicino alle attività pull di Task Queues.

Pub/Sub offre più funzionalità rispetto alla funzionalità pull fornita da Task Queue. Ad esempio, Pub/Sub dispone anche della funzionalità push, ma Cloud Tasks è più simile alle attività push di Task Queue, quindi il push di Pub/Sub non è coperto da nessuno dei moduli di migrazione. Questo codelab del modulo 19 mostra il passaggio dal meccanismo di gestione delle code dalle code pull di Task Queue a Pub/Sub, nonché la migrazione da App Engine NDB a Cloud NDB per l'accesso a Datastore, ripetendo la migrazione del modulo 2.

Sebbene il codice del modulo 18 sia "pubblicizzato" come app di esempio Python 2, l'origine stessa è compatibile con Python 2 e 3 e rimane tale anche dopo la migrazione a Cloud Pub/Sub (e Cloud NDB) nel modulo 19.

Questo tutorial prevede i seguenti passaggi:

  1. Configurazione/preparazione
  2. Aggiorna configurazione
  3. Modificare il codice dell'applicazione

3. Configurazione/preparazione

Questa sezione spiega come:

  1. Configura il progetto cloud
  2. Ottieni l'app di esempio di base
  3. (R)esegui il deployment e convalida l'app di riferimento
  4. Abilitare nuovi servizi/API Google Cloud

Questi passaggi assicurano che tu stia iniziando con un codice funzionante e che sia pronto per la migrazione ai servizi cloud.

1. Configura il progetto

Se hai completato il codelab del modulo 18, riutilizza lo stesso progetto (e codice). In alternativa, crea un nuovo progetto o riutilizza un altro progetto esistente. Assicurati che il progetto abbia un account di fatturazione attivo e un'app App Engine abilitata. Trova l'ID progetto, in quanto ti servirà durante questo codelab. Utilizzalo ogni volta che incontri la variabile PROJECT_ID.

2. Ottieni l'app di esempio di base

Uno dei prerequisiti è un'app App Engine del modulo 18 funzionante, quindi completa il relativo codelab (consigliato; link sopra) o copia il codice del modulo 18 dal repository. Che tu utilizzi il tuo o il nostro, è qui che inizieremo ("INIZIO"). Questo codelab ti guida nella migrazione e si conclude con un codice simile a quello presente nella cartella del repository del modulo 19 ("FINISH").

Indipendentemente dall'app del Modulo 18 che utilizzi, la cartella dovrebbe essere simile a quella riportata di seguito, possibilmente con anche una cartella lib:

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

3. (R)esegui il deployment e convalida l'app di riferimento

Esegui i seguenti passaggi per eseguire il deployment dell'app Modulo 18:

  1. Elimina la cartella lib, se presente, ed esegui pip install -t lib -r requirements.txt per ripopolare lib. Potresti dover utilizzare pip2 se hai installato sia Python 2 che 3 sulla tua macchina di sviluppo.
  2. Assicurati di aver installato e inizializzato lo strumento a riga di comando gcloud e di averne esaminato l'utilizzo.
  3. (Facoltativo) Imposta il tuo progetto cloud con gcloud config set project PROJECT_ID se non vuoi inserire PROJECT_ID con ogni comando gcloud che emetti.
  4. Esegui il deployment dell'app di esempio con gcloud app deploy
  5. Verifica che l'app funzioni come previsto senza problemi. Se hai completato il codelab del modulo 18, l'app mostra i principali visitatori insieme alle visite più recenti (come illustrato di seguito). In caso contrario, potrebbero non essere disponibili conteggi delle visite da visualizzare.

b667551dcbab1a09.png

Prima di eseguire la migrazione dell'app di esempio del modulo 18, devi prima abilitare i servizi cloud che verranno utilizzati dall'app modificata.

4. Abilitare nuovi servizi/API Google Cloud

La vecchia app utilizzava i servizi in bundle di App Engine, che non richiedono configurazione aggiuntiva, ma i servizi Cloud autonomi sì. L'app aggiornata utilizzerà sia Cloud Pub/Sub sia Cloud Datastore (tramite la libreria client Cloud NDB). App Engine e entrambe le API Cloud hanno quote del livello "Sempre senza costi" e, finché rispetti questi limiti, non dovresti sostenere costi per completare questo tutorial. Le API Cloud possono essere abilitate dalla console Cloud o dalla riga di comando, a seconda delle tue preferenze.

Dalla console Cloud

Vai alla pagina della libreria di API Manager (per il progetto corretto) in Cloud Console e cerca le API Cloud Datastore e Cloud Pub/Sub utilizzando la barra di ricerca al centro della pagina:

c7a740304e9d35b.png

Fai clic sul pulsante Attiva per ogni API separatamente. Potrebbe esserti chiesto di fornire i dati di fatturazione. Ad esempio, questa è la pagina della libreria API Cloud Pub/Sub:

1b6c0a2a73124f6b.jpeg

Dalla riga di comando

Sebbene l'abilitazione delle API dalla console sia visivamente informativa, alcuni preferiscono la riga di comando. Esegui il comando gcloud services enable pubsub.googleapis.com datastore.googleapis.com per abilitare entrambe le API contemporaneamente:

$ gcloud services enable pubsub.googleapis.com datastore.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Potrebbe esserti richiesto di inserire i dati di fatturazione. Se vuoi abilitare altre API Cloud e vuoi sapere quali sono i loro URI, puoi trovarli in fondo alla pagina della libreria di ogni API. Ad esempio, osserva pubsub.googleapis.com come "Nome servizio" nella parte inferiore della pagina Pub/Sub appena sopra.

Una volta completati i passaggi, il tuo progetto potrà accedere alle API. Ora è il momento di aggiornare l'applicazione per utilizzare queste API.

4. Crea risorse Pub/Sub

Riepilogo dell'ordine della sequenza del flusso di lavoro della coda delle attività del modulo 18:

  1. Il modulo 18 ha utilizzato il file queue.yaml per creare una coda pull denominata pullq.
  2. L'app aggiunge attività alla coda pull per monitorare i visitatori.
  3. Le attività vengono alla fine elaborate da un worker, noleggiato per un periodo di tempo finito (un'ora).
  4. Le attività vengono eseguite per conteggiare i visitatori recenti.
  5. Le attività vengono eliminate dalla coda al termine.

Replicherai un flusso di lavoro simile con Pub/Sub. La sezione successiva introduce la terminologia di base di Pub/Sub, con tre modi diversi per creare le risorse Pub/Sub necessarie.

Terminologia di App Engine Task Queue (pull) e Cloud Pub/Sub

Il passaggio a Pub/Sub richiede un leggero aggiustamento del vocabolario. Di seguito sono elencate le categorie principali insieme ai termini pertinenti di entrambi i prodotti. Consulta anche la guida alla migrazione, che include confronti simili.

  • Struttura dei dati di accodamento:con Task Queue, i dati vengono inseriti nelle code pull; con Pub/Sub, i dati vengono inseriti negli argomenti.
  • Unità di dati in coda: le attività pull con la coda di attività sono chiamate messaggi con Pub/Sub.
  • Responsabili del trattamento dei dati:con Task Queue, i worker accedono alle attività pull; con Pub/Sub, hai bisogno di abbonamenti/abbonati per ricevere i messaggi
  • Estrazione dei dati: leasing di un'attività pull equivale a estrarre un messaggio da un argomento (tramite un abbonamento).
  • Pulizia/completamento: l'eliminazione di un'attività Task Queues da una coda pull al termine dell'operazione è analoga al riconoscimento di un messaggio Pub/Sub

Anche se la messa in coda dei prodotti cambia, il flusso di lavoro rimane relativamente simile:

  1. Anziché una coda pull, l'app utilizza un argomento denominato pullq.
  2. Anziché aggiungere attività a una coda pull, l'app invia messaggi a un argomento (pullq).
  3. Anziché un worker che prende in leasing le attività dalla coda pull, un sottoscrittore denominato worker estrae i messaggi dall'argomento pullq.
  4. L'app elabora i payload dei messaggi, incrementando i conteggi dei visitatori in Datastore.
  5. Anziché eliminare le attività dalla coda pull, l'app riconosce i messaggi elaborati.

Con Task Queue, la configurazione prevede la creazione della coda pull. Con Pub/Sub, la configurazione richiede la creazione di un argomento e di una sottoscrizione. Nel modulo 18 abbiamo elaborato queue.yaml al di fuori dell'esecuzione dell'app; ora dobbiamo fare lo stesso con Pub/Sub.

Esistono tre opzioni per creare argomenti e sottoscrizioni:

  1. Dalla console Cloud
  2. Dalla riga di comando o
  3. Dal codice (breve script Python)

Scegli una delle opzioni riportate di seguito e segui le istruzioni corrispondenti per creare le risorse Pub/Sub.

Dalla console Cloud

Per creare un argomento dalla console Cloud, segui questi passaggi:

  1. Vai alla pagina Argomenti Pub/Sub della console Cloud.
  2. Fai clic su Crea argomento in alto; si apre una nuova finestra di dialogo (vedi immagine sotto)
  3. Nel campo ID argomento, inserisci pullq.
  4. Deseleziona tutte le opzioni selezionate e seleziona Chiave di crittografia gestita da Google.
  5. Fai clic sul pulsante Crea argomento.

Ecco l'aspetto della finestra di dialogo per la creazione di argomenti:

a05cfdbf64571ceb.png

Ora che hai un argomento, devi creare una sottoscrizione per quell'argomento:

  1. Vai alla pagina Sottoscrizioni Pub/Sub della console Cloud.
  2. Fai clic su Crea abbonamento in alto (vedi immagine sotto).
  3. Inserisci worker nel campo ID sottoscrizione.
  4. Scegli pullq dal menu a discesa Seleziona un argomento Cloud Pub/Sub, annotando il "pathname completo", ad esempio projects/PROJECT_ID/topics/pullq
  5. Per Tipo di consegna, seleziona Pull.
  6. Lascia invariate tutte le altre opzioni e fai clic sul pulsante Crea.

Ecco come appare la schermata di creazione dell'abbonamento:

c5444375c20b0618.jpeg

Puoi anche creare una sottoscrizione dalla pagina Argomenti. Questa "scorciatoia" potrebbe esserti utile per associare gli argomenti alle sottoscrizioni. Per saperne di più sulla creazione di abbonamenti, consulta la documentazione.

Dalla riga di comando

Gli utenti Pub/Sub possono creare argomenti e sottoscrizioni con i comandi gcloud pubsub topics create TOPIC_ID e gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID, rispettivamente. L'esecuzione di questi comandi con un TOPIC_ID di pullq e un SUBSCRIPTION_ID di worker produce il seguente output per il progetto 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].

Consulta anche questa pagina nella documentazione della guida rapida. L'utilizzo della riga di comando potrebbe semplificare i flussi di lavoro in cui vengono creati regolarmente argomenti e abbonamenti e questi comandi possono essere utilizzati negli script shell a questo scopo.

Dal codice (breve script Python)

Un altro modo per automatizzare la creazione di argomenti e sottoscrizioni è utilizzare l'API Pub/Sub nel codice sorgente. Di seguito è riportato il codice per lo script maker.py nella cartella del repository del modulo 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()

L'esecuzione di questo script produce l'output previsto (a condizione che non ci siano errori):

$ python3 maker.py
Created topic 'pullq' (projects/PROJECT_ID/topics/pullq)
Subscription created 'worker' (projects/PROJECT_ID/subscriptions/worker)

La chiamata all'API per creare risorse già esistenti genera un'eccezione google.api_core.exceptions.AlreadyExists generata dalla libreria client, gestita correttamente dallo 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 non hai mai utilizzato Pub/Sub, consulta il white paper sull'architettura di Pub/Sub per ulteriori informazioni.

5. Aggiorna configurazione

Gli aggiornamenti alla configurazione includono sia la modifica di vari file di configurazione sia la creazione dell'equivalente delle code pull di App Engine, ma all'interno dell'ecosistema Cloud Pub/Sub.

Elimina queue.yaml

Stiamo abbandonando completamente Task Queue, quindi elimina queue.yaml perché Pub/Sub non utilizza questo file. Anziché creare una coda pull, creerai un argomento Pub/Sub (e una sottoscrizione).

requirements.txt

Aggiungi sia google-cloud-ndb che google-cloud-pubsub a requirements.txt per partecipare a flask dal modulo 18. Il modulo 19 aggiornato requirements.txt dovrebbe ora avere questo aspetto:

flask
google-cloud-ndb
google-cloud-pubsub

Questo file requirements.txt non include numeri di versione, il che significa che sono selezionate le versioni più recenti. In caso di incompatibilità, segui la prassi standard di utilizzo dei numeri di versione per bloccare le versioni funzionanti di un'app.

app.yaml

Le modifiche a app.yaml variano a seconda che tu rimanga con Python 2 o esegua l'upgrade a Python 3.

Python 2

L'aggiornamento precedente a requirements.txt aggiunge l'utilizzo delle librerie client di Google Cloud. Questi richiedono un supporto aggiuntivo da parte di App Engine, ovvero un paio di librerie integrate, setuptools e grpcio. L'utilizzo di librerie integrate richiede una sezione libraries in app.yaml e i numeri di versione della libreria o "latest" per la versione più recente disponibile sui server App Engine. Il modulo 18 app.yaml non ha ancora una di queste sezioni:

PRIMA:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

Aggiungi una sezione libraries a app.yaml insieme alle voci per setuptools e grpcio, selezionando le loro ultime versioni. Aggiungi anche una voce segnaposto runtime per Python 3, commentata insieme a una release 3.x attuale, ad esempio 3.10, al momento della stesura di questo articolo. Con queste modifiche, app.yaml ora ha il seguente aspetto:

DOPO:

#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

Per gli utenti di Python 3 e app.yaml, si tratta di rimuovere elementi. In questa sezione eliminerai la sezione handlers, le direttive threadsafe e api_version e non creerai una sezione libraries.

I runtime di seconda generazione non forniscono librerie di terze parti integrate, pertanto non è necessaria una sezione libraries in app.yaml. Inoltre, non è più necessario copiare (a volte noto come vendoring o self-bundling) pacchetti di terze parti non integrati. Devi elencare solo le librerie di terze parti utilizzate dalla tua app in requirements.txt.

La sezione handlers in app.yaml serve per specificare i gestori di applicazioni (script) e file statici. Poiché il runtime Python 3 richiede che i framework web eseguano il proprio routing, tutti i gestori di script devono essere modificati in auto. Se la tua app (come quella del modulo 18) non gestisce file statici, tutte le route sarebbero auto, il che le renderebbe irrilevanti. Di conseguenza, non è necessaria nemmeno la sezione handlers, quindi eliminala.

Infine, le direttive threadsafe e api_version non vengono utilizzate in Python 3, quindi eliminale. Il risultato finale è che devi eliminare tutte le sezioni di app.yaml in modo che rimanga solo la direttiva runtime, che specifica una versione moderna di Python 3, ad esempio 3.10. Ecco come si presenta app.yaml prima e dopo questi aggiornamenti:

PRIMA:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

DOPO:

runtime: python310

Per chi non è pronto a eliminare tutto da app.yaml per Python 3, abbiamo fornito un file alternativo app3.yaml nella cartella del repository del modulo 19. Se vuoi utilizzarlo per le implementazioni, assicurati di aggiungere questo nome file alla fine del comando: gcloud app deploy app3.yaml (altrimenti, verrà utilizzato per impostazione predefinita e verrà eseguita l'implementazione dell'app con il file app.yaml Python 2 che hai lasciato invariato).

appengine_config.py

Se esegui l'upgrade a Python 3, non è necessario appengine_config.py, quindi eliminalo. Il motivo per cui non è necessario è che il supporto delle librerie di terze parti richiede solo di specificarle in requirements.txt. Utenti di Python 2, continua a leggere.

Il modulo 18 appengine_config.py contiene il codice appropriato per supportare librerie di terze parti, ad esempio Flask e le librerie client di Cloud appena aggiunte a requirements.txt:

PRIMA:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Tuttavia, questo codice da solo non è sufficiente per supportare le librerie integrate appena aggiunte (setuptools, grpcio). Sono necessarie alcune righe aggiuntive, quindi aggiorna appengine_config.py in modo che sia simile a questo:

DOPO:

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)

Per ulteriori dettagli sulle modifiche necessarie per supportare le librerie client Cloud, consulta la documentazione sulla migrazione dei servizi in bundle.

Altri aggiornamenti della configurazione

Se hai una cartella lib, eliminala. Se utilizzi Python 2, ripristina la cartella lib eseguendo questo comando:

pip install -t lib -r requirements.txt  # or pip2

Se hai installato sia Python 2 sia Python 3 sul tuo sistema di sviluppo, potresti dover utilizzare pip2 anziché pip.

6. Modificare il codice dell'applicazione

Questa sezione include aggiornamenti al file dell'applicazione principale, main.py, che sostituiscono l'utilizzo delle code pull di App Engine Task Queue con Cloud Pub/Sub. Non sono state apportate modifiche al modello web templates/index.html. Entrambe le app dovrebbero funzionare in modo identico, visualizzando gli stessi dati.

Aggiornare le importazioni e l'inizializzazione

Sono stati apportati diversi aggiornamenti a importazioni e inizializzazione:

  1. Per le importazioni, sostituisci App Engine NDB e la coda di attività con Cloud NDB e Pub/Sub.
  2. Rinomina pullq da un nome QUEUE a un nome TOPIC.
  3. Con i pull task, il lavoratore li ha presi in leasing per un'ora, ma con Pub/Sub i timeout vengono misurati in base al messaggio, quindi elimina la costante HOUR.
  4. Le API Cloud richiedono l'utilizzo di un client API, quindi inizializza quelli per Cloud NDB e Cloud Pub/Sub, con quest'ultimo che fornisce client sia per gli argomenti che per gli abbonamenti.
  5. Pub/Sub richiede l'ID progetto Cloud, quindi importalo e recuperalo da google.auth.default().
  6. Pub/Sub richiede "nomi di percorso completi" per argomenti e sottoscrizioni, quindi creali utilizzando le funzioni di convenienza *_path().

Di seguito sono riportati le importazioni e l'inizializzazione del modulo 18, seguite da come dovrebbero apparire le sezioni dopo l'implementazione delle modifiche riportate sopra, con la maggior parte del nuovo codice costituito da varie risorse Pub/Sub:

PRIMA:

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__)

DOPO:

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)

Visita la pagina Aggiornamenti del modello dati

Il modello di dati Visit non cambia. L'accesso a Datastore richiede l'utilizzo esplicito del gestore del contesto del client API Cloud NDB, ds_client.context(). Nel codice, ciò significa racchiudere le chiamate Datastore sia in store_visit() sia in fetch_visits() all'interno dei blocchi with di Python. Questo aggiornamento è identico a quello trattato nel modulo 2.

La modifica più pertinente per Pub/Sub è la sostituzione dell'accodamento di un'attività pull di Task Queue con la pubblicazione di un messaggio Pub/Sub nell'argomento pullq. Di seguito è riportato il codice prima e dopo aver apportato questi aggiornamenti:

PRIMA:

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)

DOPO:

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)

Aggiornamenti del modello di dati VisitorCount

Il modello di dati VisitorCount non cambia e non fa fetch_counts(), tranne per il wrapping della query Datastore all'interno di un blocco with, come illustrato di seguito:

PRIMA:

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)

DOPO:

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)

Aggiorna codice del lavoratore

Il codice del worker viene aggiornato sostituendo NDB con Cloud NDB e Task Queue con Pub/Sub, ma il flusso di lavoro rimane lo stesso.

  1. Includi le chiamate Datastore nel blocco del gestore di contesto Cloud NDB with.
  2. La pulizia della coda delle attività prevede l'eliminazione di tutte le attività dalla coda pull. Con Pub/Sub, gli "ID riconoscimento" vengono raccolti in acks e poi eliminati/riconosciuti alla fine.
  3. Le attività pull di Task Queue vengono affittate in modo simile a come vengono recuperati i messaggi Pub/Sub. Mentre l'eliminazione delle attività pull viene eseguita con gli oggetti attività stessi, i messaggi Pub/Sub vengono eliminati tramite i relativi ID di riconoscimento.
  4. I payload dei messaggi Pub/Sub richiedono byte (non stringhe Python), quindi è necessaria la codifica e la decodifica UTF-8 quando si pubblicano e si recuperano messaggi da un argomento, rispettivamente.

Sostituisci log_visitors() con il codice aggiornato riportato di seguito, che implementa le modifiche appena descritte:

PRIMA:

@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))

DOPO:

@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))

Non sono state apportate modifiche al gestore principale dell'applicazione root(). Non sono necessarie modifiche nemmeno nel file modello HTML, templates/index.html, quindi questo conclude tutti gli aggiornamenti necessari. Congratulazioni per aver creato la tua nuova applicazione del modulo 19 utilizzando Cloud Pub/Sub.

7. Riepilogo/Pulizia

Esegui il deployment dell'app per verificare che funzioni come previsto e in qualsiasi output riflesso. Esegui anche il worker per elaborare i conteggi dei visitatori. Dopo la convalida dell'app, esegui i passaggi di pulizia e valuta i passaggi successivi.

Esegui il deployment e verifica l'applicazione

Assicurati di aver già creato l'argomento pullq e la sottoscrizione worker. Se hai completato questa operazione e la tua app di esempio è pronta, esegui il deployment dell'app con gcloud app deploy. L'output dovrebbe essere identico all'app del modulo 18, tranne per il fatto che hai sostituito correttamente l'intero meccanismo di gestione delle code sottostante:

b667551dcbab1a09.png

Il frontend web dell'app ora verifica che questa parte dell'applicazione funzioni. Sebbene questa parte dell'app esegua correttamente query e visualizzi i visitatori principali e le visite più recenti, ricorda che l'app registra questa visita e crea un'attività di estrazione per aggiungere questo visitatore al conteggio complessivo. L'attività è ora in coda in attesa di essere elaborata.

Puoi eseguire questa operazione con un servizio di backend App Engine, un job cron, accedendo a /log o inviando una richiesta HTTP dalla riga di comando. Di seguito è riportato un esempio di esecuzione e output della chiamata al codice del worker con curl (sostituisci PROJECT_ID):

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

Il conteggio aggiornato verrà visualizzato alla visita successiva del sito web. È tutto.

Esegui la pulizia

Generale

Se hai finito per il momento, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi fare altri test o esperimenti, la piattaforma App Engine ha una quota senza costi e, finché non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il calcolo, ma potrebbero essere addebitati anche costi per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se questa migrazione coinvolge altri servizi cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifiche per questo codelab" di seguito.

Per una divulgazione completa, il deployment su una piattaforma di calcolo serverless di Google Cloud come App Engine comporta costi di build e archiviazione minimi. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte della quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni sotto controllo l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" Cloud Storage specifiche che devi esaminare includono:

  • 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
  • I link di archiviazione riportati sopra dipendono dalla tua PROJECT_ID e dalla tua *LOC*, ad esempio "us" se la tua app è ospitata negli Stati Uniti.

D'altra parte, se non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto completamente, chiudi il progetto.

Specifico per questo codelab

I servizi elencati di seguito sono univoci per questo codelab. Per saperne di più, consulta la documentazione di ogni prodotto:

  • I diversi componenti di Cloud Pub/Sub hanno un livello senza costi; determina l'utilizzo complessivo per avere un'idea migliore delle implicazioni sui costi e consulta la pagina dei prezzi per ulteriori dettagli.
  • Il servizio App Engine Datastore è fornito da Cloud Datastore (Cloud Firestore in modalità Datastore), che dispone anche di un livello senza costi. Per ulteriori informazioni, consulta la pagina dei prezzi.

Passaggi successivi

Oltre a questo tutorial, altri moduli di migrazione che si concentrano sul passaggio dai servizi in bundle legacy da prendere in considerazione includono:

  • Modulo 2: esegui la migrazione da App Engine ndb a Cloud NDB
  • Moduli 7-9: esegui la migrazione da App Engine Task Queue (attività push) a Cloud Tasks
  • Moduli 12-13: esegui la migrazione da Memcache App Engine a Cloud Memorystore
  • Moduli 15-16: esegui la migrazione da App Engine Blobstore a Cloud Storage

App Engine non è più l'unica piattaforma serverless in Google Cloud. Se hai una piccola app App Engine o una con funzionalità limitate e vuoi trasformarla in un microservizio autonomo oppure vuoi suddividere un'app monolitica in più componenti riutilizzabili, questi sono buoni motivi per prendere in considerazione il passaggio a Cloud Functions. Se la containerizzazione è diventata parte del flusso di lavoro di sviluppo delle applicazioni, in particolare se consiste in una pipeline CI/CD (integrazione continua/distribuzione continua o deployment continuo), valuta la migrazione a Cloud Run. Questi scenari sono trattati nei seguenti moduli:

  • Esegui la migrazione da App Engine a Cloud Functions: consulta il modulo 11
  • Esegui la migrazione da App Engine a Cloud Run: consulta il modulo 4 per inserire la tua app in un container con Docker o il modulo 5 per farlo senza container, conoscenze di Docker o Dockerfiles

Il passaggio a un'altra piattaforma serverless è facoltativo e ti consigliamo di valutare le opzioni migliori per le tue app e i tuoi casi d'uso prima di apportare modifiche.

Indipendentemente dal modulo di migrazione che prenderai in considerazione, tutti i contenuti di Serverless Migration Station (codelab, video, codice sorgente [se disponibile]) sono accessibili nel relativo repository open source. Il repository README fornisce anche indicazioni sulle migrazioni da prendere in considerazione e sull'eventuale "ordine" dei moduli di migrazione pertinenti.

8. Risorse aggiuntive

Di seguito sono elencate risorse aggiuntive per gli sviluppatori che vogliono esplorare ulteriormente questo modulo di migrazione o quelli correlati, nonché i prodotti correlati. Sono inclusi i luoghi in cui fornire feedback su questi contenuti, i link al codice e vari documenti che potresti trovare utili.

Problemi/feedback relativi a Codelab

Se riscontri problemi con questo codelab, cerca prima il tuo problema prima di presentare una segnalazione. Link per cercare e creare nuovi problemi:

Risorse per la migrazione

I link alle cartelle del repository per il Modulo 18 (INIZIO) e il Modulo 19 (FINE) sono riportati nella tabella seguente.

Codelab

Python 2

Python 3

Modulo 18

code

(n/a)

Modulo 19 (questo codelab)

code

(come per Python 2, tranne che devi utilizzare app3.yaml, a meno che tu non abbia aggiornato app.yaml come descritto sopra)

Riferimenti online

Di seguito sono riportate le risorse pertinenti per questo tutorial:

Coda delle attività App Engine

Cloud Pub/Sub

App Engine NDB e Cloud NDB (Datastore)

Piattaforma App Engine

Altre informazioni sul cloud

Video

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.