Migrer des tâches d'extraction de la file d'attente de tâches App Engine vers Cloud Pub/Sub (module 19)

1. Présentation

La série d'ateliers de programmation sur la station de migration sans serveur (tutoriels pratiques et d'auto-formation) et les vidéos associées visent à aider les développeurs sans serveur Google Cloud à moderniser leurs applications en les guidant dans une ou plusieurs migrations, principalement en abandonnant les anciens services. Vous améliorez ainsi la portabilité de vos applications, et vous bénéficiez de plus d'options et de flexibilité. Vous pouvez ainsi intégrer un plus large éventail de produits Cloud et y accéder, et passer plus facilement à de nouvelles langues. Bien qu'elle s'adresse initialement aux utilisateurs les plus anciens du cloud, principalement les développeurs d'environnements App Engine (standard), cette série est suffisamment large pour inclure d'autres plates-formes sans serveur telles que Cloud Functions et Cloud Run, ou ailleurs, le cas échéant.

L'objectif de cet atelier de programmation est de montrer aux développeurs Python 2 App Engine comment migrer des tâches d'extraction de la file d'attente des tâches App Engine vers Cloud Pub/Sub. Il existe également une migration implicite d'App Engine NDB vers Cloud NDB pour l'accès à Datastore (principalement abordée dans le module 2), ainsi qu'une mise à niveau vers Python 3.

Dans le module 18, vous apprendrez à ajouter l'utilisation de tâches pull à votre application. Dans ce module, vous allez utiliser l'application du module 18 terminée et migrer son utilisation vers Cloud Pub/Sub. Ceux qui utilisent les files d'attente pour les tâches push migrent vers Cloud Tasks et doivent, à la place, se reporter aux modules 7 à 9.

Vous apprendrez à

Prérequis

Enquête

Comment allez-vous utiliser ce tutoriel ?

<ph type="x-smartling-placeholder"></ph> Je vous invite à le lire uniquement Je vais le lire et effectuer les exercices

Quel est votre niveau d'expérience avec Python ?

Débutant Intermédiaire Expert

Quel est votre niveau d'expérience avec les services Google Cloud ?

<ph type="x-smartling-placeholder"></ph> Débutant Intermédiaire Expert
.

2. Contexte

La file d'attente de tâches App Engine accepte les tâches d'envoi et de retrait. Pour améliorer la portabilité des applications, Google Cloud recommande de migrer des anciens services groupés tels que Task Queue vers d'autres services cloud autonomes ou équivalents.

Les modules 7 à 9 traitent de la migration des tâches d'envoi, tandis que les modules 18 à 19 sont consacrés à la migration des tâches d'extraction. Bien que Cloud Tasks corresponde plus précisément aux tâches d'envoi de la file d'attente de tâches, Pub/Sub n'est pas aussi proche des tâches d'extraction de la file d'attente de tâches.

Pub/Sub offre plus de fonctionnalités que la fonctionnalité d'extraction fournie par la file d'attente de tâches. Par exemple, Pub/Sub dispose également de la fonctionnalité push, mais Cloud Tasks ressemble davantage aux tâches d'envoi de file d'attente de tâches. La transmission push Pub/Sub n'est donc pas couverte par les modules de migration. Dans cet atelier de programmation du module 19, vous verrez comment faire passer le mécanisme de mise en file d'attente des files d'attente de retrait de la file d'attente de tâches à Pub/Sub, ainsi qu'effectuer la migration d'App Engine NDB vers Cloud NDB pour accéder à Datastore, en répétant la migration du module 2.

Alors que le code du module 18 est "annoncé" en tant qu'application exemple Python 2, la source elle-même est compatible avec Python 2 et 3, et elle le reste même après la migration vers Cloud Pub/Sub (et Cloud NDB) dans le module 19.

Ce tutoriel comprend les étapes suivantes:

  1. Configuration/Préparation
  2. Mettre à jour la configuration
  3. Modifier le code d'application

3. Configuration/Préparation

Cette section explique comment effectuer les opérations suivantes :

  1. Configurer votre projet Cloud
  2. Obtenir un exemple d'application de référence
  3. (Re)Déployer et valider l'application de référence
  4. Activer de nouveaux services/API Google Cloud

Cette procédure permet de s'assurer que vous commencez avec du code fonctionnel et qu'il est prêt pour la migration vers les services Cloud.

1. Configurer le projet

Si vous avez terminé l'atelier de programmation du module 18, réutilisez ce projet (et ce même code). Vous pouvez également créer un projet ou réutiliser un autre projet existant. Assurez-vous que le projet dispose d'un compte de facturation actif et d'une application App Engine activée. Recherchez l'ID de votre projet, car vous en aurez besoin au cours de cet atelier de programmation. Utilisez-le chaque fois que vous rencontrez la variable PROJECT_ID.

2. Obtenir un exemple d'application de référence

L'une des conditions préalables est une application App Engine opérationnelle du module 18. Vous devez donc suivre son atelier de programmation (recommandé ; lien ci-dessus) ou copier le code du module 18 à partir du dépôt. Que vous utilisiez la vôtre ou la nôtre, c'est ici que nous allons commencer ("DÉMARRER"). Cet atelier de programmation vous guide tout au long de la migration et se termine par un code ressemblant à celui du dossier du dépôt du module 19 ("FINISH").

Quelle que soit l'application du module 18 que vous utilisez, le dossier doit se présenter comme suit, éventuellement avec un dossier lib:

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

3. (Re)Déployer et valider l'application de référence

Exécutez les étapes suivantes pour déployer l'application du module 18:

  1. Supprimez le dossier lib s'il y en a un, puis exécutez pip install -t lib -r requirements.txt pour remplir à nouveau lib. Si Python 2 et 3 sont installés sur votre ordinateur de développement, vous devrez peut-être utiliser pip2 à la place.
  2. Assurez-vous d'avoir installé et initialisé l'outil de ligne de commande gcloud, et vérifié son utilisation.
  3. (Facultatif) Définissez votre projet Cloud avec gcloud config set project PROJECT_ID si vous ne souhaitez pas saisir PROJECT_ID avec chaque commande gcloud que vous émettez.
  4. Déployer l'exemple d'application avec gcloud app deploy
  5. Vérifiez que l'application fonctionne comme prévu sans problème. Si vous avez terminé l'atelier de programmation du module 18, l'application affiche les principaux visiteurs ainsi que les visites les plus récentes (voir ci-dessous). Si ce n'est pas le cas, il est possible qu'il n'y ait pas de nombre de visiteurs à afficher.

b667551dcbab1a09.png

Avant de migrer l'application exemple du module 18, vous devez activer les services cloud que l'application modifiée utilisera.

4. Activer de nouveaux services/API Google Cloud

L'ancienne application utilisait des services groupés App Engine qui ne nécessitent pas de configuration supplémentaire, contrairement aux services Cloud autonomes. L'application mise à jour utilisera à la fois Cloud Pub/Sub et Cloud Datastore (via la bibliothèque cliente Cloud NDB). App Engine et les deux API Cloud proposent le niveau "Toujours sans frais" de niveau supérieur, et tant que vous ne dépassez pas ces limites, aucuns frais ne devraient vous être facturés pour suivre ce tutoriel. Vous pouvez activer les API Cloud à partir de la console Cloud ou de la ligne de commande, selon vos préférences.

Depuis Cloud Console

Dans Cloud Console, accédez à la page Bibliothèque du gestionnaire d'API (pour le projet approprié), puis recherchez les API Cloud Datastore et Cloud Pub/Sub à l'aide de la barre de recherche au milieu de la page:

c7a740304e9d35b.png

Cliquez sur le bouton Activer pour chaque API séparément. Vous serez peut-être invité à saisir vos informations de facturation. Par exemple, voici la page de la bibliothèque de l'API Cloud Pub/Sub:

1b6c0a2a73124f6b.jpeg

Depuis la ligne de commande

Bien qu'elle soit visuellement utile pour activer les API de la console, certaines préfèrent utiliser la ligne de commande. Exécutez la commande gcloud services enable pubsub.googleapis.com datastore.googleapis.com pour activer les deux API en même temps:

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

Vous serez peut-être invité à saisir vos informations de facturation. Si vous souhaitez activer d'autres API Cloud et connaître leurs URI, vous les trouverez en bas de la page de la bibliothèque de chaque API. Par exemple, observez pubsub.googleapis.com comme le "nom du service". au bas de la page Pub/Sub juste au-dessus.

Une fois ces étapes terminées, votre projet pourra accéder aux API. Il est maintenant temps de mettre à jour l'application pour utiliser ces API.

4. Créer les ressources Pub/Sub

Récapitulons l'ordre séquentiel du workflow de la file d'attente de tâches du module 18:

  1. Le module 18 a utilisé le fichier queue.yaml pour créer une file d'attente de retrait nommée pullq.
  2. L'application ajoute des tâches à la file d'attente de retrait pour suivre les visiteurs.
  3. Les tâches finissent par être traitées par un nœud de calcul, qui est loué pour une durée limitée (une heure).
  4. Les tâches sont exécutées en fonction du nombre de visiteurs récents.
  5. Les tâches sont supprimées de la file d'attente une fois terminées.

Vous allez répliquer un workflow similaire avec Pub/Sub. La section suivante présente la terminologie de base de Pub/Sub, ainsi que trois méthodes différentes pour créer les ressources Pub/Sub nécessaires.

Terminologie liée aux files d'attente de tâches App Engine (pull) et Cloud Pub/Sub

Passer à Pub/Sub nécessite un léger ajustement de votre vocabulaire. Vous trouverez ci-dessous les catégories principales, ainsi que les termes associés aux deux produits. Consultez également le guide de migration, qui propose des comparaisons similaires.

  • Mise en file d'attente de la structure des données:avec la file d'attente de tâches, les données sont placées dans des files d'attente de retrait. avec Pub/Sub, les données sont stockées dans des sujets.
  • Unités de données en file d'attente : les tâches d'extraction avec Task Queue sont appelées messages avec Pub/Sub.
  • Processeurs de données:avec la file d'attente de tâches, les nœuds de calcul accèdent aux tâches d'extraction. avec Pub/Sub, vous avez besoin d'abonnements/abonnés pour recevoir des messages
  • Extraction de données : louer une tâche d'extraction revient à extraire un message d'un sujet (via un abonnement).
  • Nettoyage/achèvement : supprimer une tâche de file d'attente de tâches d'une file d'attente de retrait lorsque vous avez terminé revient à confirmer la réception d'un message Pub/Sub.

Bien que le produit mis en file d'attente change, le workflow reste relativement similaire:

  1. Plutôt qu'une file d'attente de retrait, l'application utilise un sujet nommé pullq.
  2. Plutôt que d'ajouter des tâches à une file d'attente de retrait, l'application envoie des messages à un sujet (pullq).
  3. Plutôt que de louer des tâches de la file d'attente de retrait, un abonné nommé worker extrait les messages du sujet pullq.
  4. L'application traite les charges utiles des messages, en incrémentant le nombre de visiteurs dans Datastore.
  5. Plutôt que de supprimer des tâches de la file d'attente de retrait, l'application accuse réception des messages traités.

Avec Task Queue, la configuration implique la création d'une file d'attente de retrait. Pour configurer Pub/Sub, vous devez créer un sujet et un abonnement. Dans le module 18, nous avons traité queue.yaml en dehors de l'exécution de l'application. Nous devons maintenant faire la même chose avec Pub/Sub.

Trois options s'offrent à vous pour créer des sujets et des abonnements:

  1. Depuis la console Cloud
  2. Depuis la ligne de commande, ou
  3. À partir du code (script Python court)

Choisissez l'une des options ci-dessous et suivez les instructions correspondantes pour créer vos ressources Pub/Sub.

Depuis la console Cloud

Pour créer un sujet à partir de la console Cloud, procédez comme suit:

  1. Accédez à la page Sujets Pub/Sub de la console Cloud.
  2. Cliquez sur Créer un sujet en haut de la page. une nouvelle boîte de dialogue s'ouvre (voir l'image ci-dessous).
  3. Dans le champ ID du sujet, saisissez pullq.
  4. Décochez toutes les options cochées, puis sélectionnez Clé de chiffrement gérée par Google.
  5. Cliquez sur le bouton Créer un sujet.

Voici à quoi ressemble la boîte de dialogue de création de sujet:

a05cfdbf64571ceb.png

Maintenant que vous disposez d'un sujet, vous devez créer un abonnement pour ce sujet:

  1. Accédez à la page Abonnements Pub/Sub de la console Cloud.
  2. Cliquez sur Créer un abonnement en haut (voir l'image ci-dessous).
  3. Saisissez worker dans le champ ID d'abonnement.
  4. Choisissez pullq dans le menu déroulant Sélectionner un sujet Cloud Pub/Sub et notez son "chemin d'accès complet". Exemple : projects/PROJECT_ID/topics/pullq
  5. Dans Type de distribution, sélectionnez Extraction.
  6. Laissez toutes les autres options telles quelles et cliquez sur le bouton Créer.

L'écran de création d'abonnement se présente comme suit:

c5444375c20b0618.jpeg

Vous pouvez également créer un abonnement depuis la page Sujets. Ce "raccourci" peut vous aider à associer des sujets aux abonnements. Pour en savoir plus sur la création d'abonnements, consultez la documentation.

Depuis la ligne de commande

Les utilisateurs Pub/Sub peuvent créer des sujets et des abonnements à l'aide des commandes gcloud pubsub topics create TOPIC_ID et gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID, respectivement. Si vous les exécutez avec une TOPIC_ID de pullq et une SUBSCRIPTION_ID de worker, vous obtenez le résultat suivant pour le projet 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].

Consultez également cette page dans la documentation du guide de démarrage rapide. L'utilisation de la ligne de commande peut simplifier les workflows dans lesquels des sujets et des abonnements sont créés régulièrement. À cette fin, ces commandes peuvent être utilisées dans des scripts shell.

À partir du code (script Python court)

Une autre façon d'automatiser la création de sujets et d'abonnements consiste à utiliser l'API Pub/Sub dans le code source. Vous trouverez ci-dessous le code du script maker.py dans le dossier du dépôt du module 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'exécution de ce script produit le résultat attendu (à condition qu'il n'y ait pas d'erreur):

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

L'appel de l'API pour créer des ressources existantes génère une exception google.api_core.exceptions.AlreadyExists générée par la bibliothèque cliente, gérée correctement par le script:

$ python3 maker.py
Topic 'pullq' already exists at 'projects/PROJECT_ID/topics/pullq'
Subscription 'worker' already exists at 'projects/PROJECT_ID/subscriptions/worker'

Si vous débutez avec Pub/Sub, consultez le livre blanc sur l'architecture Pub/Sub pour obtenir plus d'informations.

5. Mettre à jour la configuration

Les mises à jour de la configuration incluent la modification de différents fichiers de configuration et la création de l'équivalent des files d'attente de retrait App Engine, mais dans l'écosystème Cloud Pub/Sub.

Supprimer le fichier queue.yaml

Comme Pub/Sub n'utilise pas ce fichier, nous allons nous éloigner complètement de la file d'attente de tâches. Par conséquent, supprimez queue.yaml. Plutôt que de créer une file d'attente de retrait, vous allez créer un sujet Pub/Sub (et un abonnement).

requirements.txt

Ajoutez google-cloud-ndb et google-cloud-pubsub à requirements.txt afin de joindre flask à partir du module 18. Le fichier requirements.txt mis à jour du module 19 doit maintenant se présenter comme suit:

flask
google-cloud-ndb
google-cloud-pubsub

Ce fichier requirements.txt ne comporte aucun numéro de version, ce qui signifie que les dernières versions sont sélectionnées. En cas d'incompatibilité, suivez la pratique standard qui consiste à utiliser des numéros de version pour verrouiller des versions fonctionnelles d'une application.

app.yaml

Les modifications apportées à app.yaml varient selon que vous utilisez Python 2 ou une mise à niveau vers Python 3.

Python 2

La mise à jour de requirements.txt ci-dessus ajoute l'utilisation des bibliothèques clientes Google Cloud. Celles-ci nécessitent une prise en charge supplémentaire d'App Engine, à savoir quelques bibliothèques intégrées, setuptools et grpcio. L'utilisation des bibliothèques intégrées nécessite une section libraries dans app.yaml et les numéros de version des bibliothèques, ou "dernière version". pour connaître les dernières nouveautés disponibles sur les serveurs App Engine. Le app.yaml du module 18 ne comporte pas encore l'une de ces sections:

AVANT:

runtime: python27
threadsafe: yes
api_version: 1

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

Ajoutez une section libraries à app.yaml, ainsi que des entrées pour setuptools et grpcio, en sélectionnant leurs dernières versions. Ajoutez également un espace réservé runtime pour Python 3, commenté avec une version 3.x actuelle (par exemple, 3.10) au moment de la rédaction de ce document. Avec ces modifications, app.yaml se présente désormais comme suit:

APRÈS:

#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

Pour les utilisateurs de Python 3 et de app.yaml, il s'agit de supprimer des éléments. Dans cette section, vous allez supprimer la section handlers, les instructions threadsafe et api_version, et vous ne créerez pas de section libraries.

Les environnements d'exécution de deuxième génération ne fournissent pas de bibliothèques tierces intégrées. Par conséquent, une section libraries n'est pas nécessaire dans app.yaml. De plus, la copie (parfois appelée "fournisseur" ou "auto-regroupement") non intégrée aux packages tiers n'est plus nécessaire. Il vous suffit de répertorier les bibliothèques tierces utilisées par votre application dans requirements.txt.

La section handlers dans app.yaml permet de spécifier les gestionnaires d'application (script) et de fichiers statiques. Étant donné que l'environnement d'exécution Python 3 nécessite que les frameworks Web effectuent leur propre routage, tous les gestionnaires de scripts doivent être remplacés par auto. Si votre application (comme celle du module 18) ne diffuse pas de fichiers statiques, toutes les routes sont alors auto, ce qui les rend non pertinentes. Par conséquent, la section handlers n'est pas non plus nécessaire. Vous devez donc la supprimer.

Enfin, les instructions threadsafe et api_version ne sont pas utilisées dans Python 3. Vous devez donc les supprimer également. En résumé, vous devez supprimer toutes les sections de app.yaml pour ne conserver que la directive runtime, en spécifiant une version moderne de Python 3, par exemple 3.10. Voici à quoi ressemble app.yaml avant et après ces mises à jour:

AVANT:

runtime: python27
threadsafe: yes
api_version: 1

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

APRÈS:

runtime: python310

Pour ceux qui ne souhaitent pas tout supprimer de leur app.yaml pour Python 3, nous avons fourni un autre fichier app3.yaml dans le dossier du dépôt du module 19. Si vous souhaitez plutôt l'utiliser pour les déploiements, veillez à ajouter ce nom de fichier à la fin de votre commande: gcloud app deploy app3.yaml. Dans le cas contraire, votre application sera déployée par défaut avec le fichier app.yaml Python 2 que vous n'avez pas modifié.

appengine_config.py

Si vous effectuez une mise à niveau vers Python 3, appengine_config.py n'est pas nécessaire. Supprimez-le. La compatibilité avec les bibliothèques tierces n'est pas nécessaire, car il suffit de les spécifier dans requirements.txt. Si vous utilisez Python 2, continuez votre lecture.

Le appengine_config.py du module 18 contient le code approprié pour les bibliothèques tierces, par exemple Flask et les bibliothèques clientes Cloud qui viennent d'être ajoutées à requirements.txt:

AVANT:

from google.appengine.ext import vendor

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

Cependant, ce code seul ne suffit pas pour prendre en charge les bibliothèques intégrées que vous venez d'ajouter (setuptools, grpcio). Quelques lignes supplémentaires sont nécessaires. Modifiez appengine_config.py pour qu'il se présente comme suit:

APRÈS:

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)

Pour en savoir plus sur les modifications requises pour prendre en charge les bibliothèques clientes Cloud, consultez la documentation sur la migration de services groupés.

Autres mises à jour de configuration

Si vous avez un dossier lib, supprimez-le. Si vous utilisez Python 2, réapprovisionnez le dossier lib en exécutant la commande suivante:

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

Si Python 2 et 3 sont installés sur votre système de développement, vous devrez peut-être utiliser pip2 au lieu de pip.

6. Modifier le code d'application

Cette section présente les mises à jour du fichier d'application principal, main.py, en remplaçant l'utilisation des files d'attente de retrait de la file d'attente des tâches App Engine par Cloud Pub/Sub. Aucune modification n'a été apportée au modèle Web, templates/index.html. Les deux applications doivent fonctionner de manière identique et afficher les mêmes données.

Mettre à jour les importations et l'initialisation

Plusieurs mises à jour sont disponibles pour les importations et l'initialisation:

  1. Pour les importations, remplacez App Engine NDB et Task Queue par Cloud NDB et Pub/Sub.
  2. Renommez pullq en remplaçant QUEUE par un nom TOPIC.
  3. Avec les tâches d'extraction, le nœud de calcul les a louées pendant une heure, mais avec Pub/Sub, les délais avant expiration sont mesurés pour chaque message. Vous devez donc supprimer la constante HOUR.
  4. Les API Cloud nécessitent l'utilisation d'un client API. Vous devez donc les lancer pour Cloud NDB et Cloud Pub/Sub, ce dernier fournissant des clients pour les sujets et les abonnements.
  5. Pub/Sub nécessite l'ID du projet Cloud. Vous devez donc l'importer et l'obtenir à partir de google.auth.default().
  6. Pub/Sub requiert des "chemins d'accès complets" pour les sujets et les abonnements. Vous devez donc les créer à l'aide des fonctions pratiques *_path().

Vous trouverez ci-dessous les importations et l'initialisation du module 18, ainsi que la façon dont les sections devraient se présenter après la mise en œuvre des modifications ci-dessus. La majeure partie du nouveau code se compose de différentes ressources Pub/Sub:

AVANT:

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

APRÈS:

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)

Accéder aux mises à jour du modèle de données

Le modèle de données Visit ne change pas. L'accès à Datastore nécessite l'utilisation explicite du gestionnaire de contexte client de l'API Cloud NDB, ds_client.context(). Dans le code, cela signifie que vous encapsulez les appels Datastore dans store_visit() et fetch_visits() dans des blocs Python with. Cette mise à jour est identique à ce qui est abordé dans le module 2.

La modification la plus pertinente pour Pub/Sub consiste à remplacer la mise en file d'attente d'une tâche d'extraction dans la file d'attente de tâches par la publication d'un message Pub/Sub dans le sujet pullq. Vous trouverez ci-dessous le code avant et après ces mises à jour:

AVANT:

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)

APRÈS:

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)

Mises à jour du modèle de données du nombre de visiteurs

Le modèle de données VisitorCount ne change pas et effectue fetch_counts(), sauf pour encapsuler sa requête Datastore dans un bloc with, comme illustré ci-dessous:

AVANT:

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)

APRÈS:

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)

Mettre à jour le code des nœuds de calcul

Le code du nœud de calcul se met à jour jusqu'au remplacement de la bibliothèque NDB par Cloud NDB et de la file d'attente de tâches avec Pub/Sub, mais son workflow reste le même.

  1. Encapsuler les appels Datastore dans le bloc with du gestionnaire de contexte Cloud NDB
  2. Le nettoyage de la file d'attente de tâches consiste à supprimer toutes les tâches de la file d'attente de retrait. Avec Pub/Sub, les "ID de confirmation" sont collectées dans acks, puis supprimées/confirmées à la fin.
  3. Les tâches d'extraction de la file d'attente de tâches sont allouées de la même manière que l'extraction des messages Pub/Sub. Alors que la suppression des tâches d'extraction est effectuée avec les objets de tâche eux-mêmes, les messages Pub/Sub sont supprimés via leurs ID de confirmation.
  4. Les charges utiles des messages Pub/Sub nécessitent des octets (et non des chaînes Python). Par conséquent, lorsque vous publiez et récupérez des messages dans un sujet, et que vous encodez et décodez UTF-8, respectivement.

Remplacez log_visitors() par le code mis à jour ci-dessous afin d'implémenter les modifications que vous venez de décrire:

AVANT:

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

APRÈS:

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

Aucune modification n'a été apportée au gestionnaire d'application principal root(). Aucune modification n'est nécessaire non plus dans le fichier de modèle HTML, templates/index.html. Toutes les mises à jour nécessaires sont ainsi incluses. Félicitations, vous avez ouvert votre nouvelle application du module 19 à l'aide de Cloud Pub/Sub !

7. Résumé/Nettoyage

Déployez votre application pour vérifier qu'elle fonctionne comme prévu et dans toutes les sorties renvoyées. Exécutez également le worker pour traiter le nombre de visiteurs. Après la validation de l'application, effectuez toutes les étapes de nettoyage et réfléchissez aux prochaines étapes.

Déployer et vérifier l'application

Assurez-vous d'avoir déjà créé le sujet pullq et l'abonnement worker. Si c'est le cas et que votre application exemple est prête à l'emploi, déployez-la avec gcloud app deploy. Le résultat doit être identique à celui de l'application du module 18, à la différence que vous avez correctement remplacé l'intégralité du mécanisme de mise en file d'attente sous-jacent:

b667551dcbab1a09.png

L'interface Web de l'application vérifie maintenant que cette partie de l'application fonctionne. Bien que cette partie de l'application interroge et affiche les principaux visiteurs et les visites les plus récentes, n'oubliez pas que l'application enregistre cette visite et crée une tâche d'extraction pour ajouter ce visiteur au décompte total. Cette tâche se trouve maintenant dans la file d'attente en attente de traitement.

Vous pouvez l'exécuter avec un service de backend App Engine, une tâche cron, en accédant à /log ou en émettant une requête HTTP de ligne de commande. Voici un exemple d'exécution qui échappe à l'appel du code de nœud de calcul avec curl (remplacez PROJECT_ID):

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

Le nouveau décompte sera ensuite reflété lors de la prochaine visite du site Web. Et voilà !

Effectuer un nettoyage

Général

Si vous avez terminé, nous vous recommandons de désactiver votre application App Engine afin d'éviter que des frais ne vous soient facturés. Toutefois, si vous souhaitez effectuer d'autres tests, la plate-forme App Engine dispose d'un quota sans frais. Tant que vous ne dépassez pas ce niveau d'utilisation, aucuns frais ne vous seront facturés. Cela concerne le calcul, mais des frais peuvent également s'appliquer pour les services App Engine concernés. Pour en savoir plus, consultez sa page des tarifs. Si cette migration implique d'autres services Cloud, ceux-ci sont facturés séparément. Dans les deux cas, le cas échéant, consultez la section "Informations spécifiques à cet atelier de programmation" ci-dessous.

Afin d'informer l'ensemble des utilisateurs, le déploiement sur une plate-forme de calcul sans serveur Google Cloud comme App Engine entraîne des coûts minimes de compilation et de stockage. Cloud Build et Cloud Storage disposent de leur propre quota sans frais. Le stockage de cette image utilise une partie de ce quota. Cependant, vous pouvez résider dans une région qui n'offre pas ce type de version sans frais. Vous devez donc surveiller l'utilisation de votre espace de stockage afin de réduire les coûts potentiels. "Dossiers" Cloud Storage spécifiques vous devez examiner:

  • 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
  • Les liens de stockage ci-dessus dépendent de votre PROJECT_ID et de votre *LOC*ation (par exemple, "us") si votre application est hébergée aux États-Unis.

En revanche, si vous ne comptez pas utiliser cette application ou d'autres ateliers de programmation liés à la migration, et que vous souhaitez tout supprimer complètement, arrêtez votre projet.

Spécifique à cet atelier de programmation

Les services listés ci-dessous sont propres à cet atelier de programmation. Pour en savoir plus, consultez la documentation de chaque produit:

  • Différents composants de Cloud Pub/Sub disposent d'une version sans frais. déterminez votre utilisation globale pour avoir une meilleure idée des implications en termes de coûts et consultez sa page de tarification pour en savoir plus.
  • Le service App Engine Datastore est fourni par Cloud Datastore (Cloud Firestore en mode Datastore), également disponible avec une version sans frais. consultez la page des tarifs pour en savoir plus.

Étapes suivantes

Au-delà de ce tutoriel, d'autres modules de migration à envisager concernant l'abandon des anciens services groupés sont les suivants:

  • Module 2: Migrer de l'environnement ndb App Engine vers Cloud NDB
  • Modules 7 à 9: migration de la file d'attente des tâches App Engine (tâches d'envoi) vers Cloud Tasks
  • Modules 12 à 13: Migrer de Memcache d'App Engine vers Cloud Memorystore
  • Modules 15 à 16: effectuer la migration d'un paquet d'application App Engine vers Cloud Storage

App Engine n'est plus la seule plate-forme sans serveur de Google Cloud. Si vous disposez d'une petite application App Engine ou d'une application aux fonctionnalités limitées et que vous souhaitez la transformer en microservice autonome, ou si vous voulez diviser une application monolithique en plusieurs composants réutilisables, nous vous recommandons de passer à Cloud Functions. Si la conteneurisation fait désormais partie de votre workflow de développement d'applications, en particulier si elle consiste en un pipeline CI/CD (intégration continue/livraison continue ou déploiement), envisagez de migrer vers Cloud Run. Ces scénarios sont abordés dans les modules suivants:

  • Effectuer une migration d'App Engine vers Cloud Functions: consultez le Module 11
  • Effectuer une migration d'App Engine vers Cloud Run: consultez le module 4 pour conteneuriser votre application avec Docker, ou le module 5 pour effectuer cette opération sans conteneur, ni connaissance de Docker ou Dockerfile.

Le passage à une autre plate-forme sans serveur est facultatif. Nous vous recommandons de réfléchir aux meilleures options pour vos applications et cas d'utilisation avant d'apporter des modifications.

Quel que soit le module de migration que vous envisagez ensuite, tout le contenu de la station de migration sans serveur (ateliers de programmation, vidéos, code source [si disponible]) est accessible dans son dépôt Open Source. Le fichier README du dépôt fournit également des indications sur les migrations à prendre en compte et sur l'ordre d'exécution approprié. des modules de migration.

8. Ressources supplémentaires

Vous trouverez ci-dessous des ressources supplémentaires destinées aux développeurs qui étudient plus en détail ce module de migration ou le module de migration associé, ainsi que les produits associés. Vous y trouverez, par exemple, des emplacements où vous pouvez envoyer des commentaires sur ce contenu, des liens vers le code et diverses documents susceptibles de vous être utiles.

Commentaires et problèmes concernant les ateliers de programmation

Si vous rencontrez des problèmes avec cet atelier de programmation, commencez par faire une recherche avant de les signaler. Liens vers la recherche et la création d'un signalement :

Ressources de migration

Le tableau ci-dessous contient des liens vers les dossiers de dépôt des modules 18 (START) et 19 (FINISH).

Atelier de programmation

Python 2

Python 3

Module 18

code

(n/a)

Module 19 (cet atelier de programmation)

code

(Identique à Python 2, mais utilisez app3.yaml, sauf si vous avez mis à jour app.yaml comme indiqué ci-dessus.)

Références en ligne

Vous trouverez ci-dessous des ressources pertinentes pour ce tutoriel:

File d'attente de tâches d'App Engine

Cloud Pub/Sub

App Engine NDB et Cloud NDB (Datastore)

Plate-forme App Engine

Autres informations sur le cloud

Vidéos

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.