Cómo usar la lista de tareas en cola de App Engine (tareas de extracción) en las apps de Flask (módulo 18)

1. Descripción general

La serie de codelabs Serverless Migration Station (instructivos prácticos y autoaprendizaje) y los videos relacionados tienen como objetivo ayudar a los desarrolladores de Google Cloud sin servidores a modernizar sus apps guiándolos a través de una o más migraciones, en especial al alejarse de los servicios heredados. De esta manera, tus apps serán más portátiles, y tendrás más opciones y flexibilidad, lo que te permitirá integrarlas con una variedad más amplia de productos de Cloud y acceder a ella, y actualizar con mayor facilidad a versiones de idiomas más recientes. Aunque inicialmente se enfoca en los primeros usuarios de Cloud, principalmente los desarrolladores de App Engine (entorno estándar), esta serie es lo suficientemente amplia como para incluir otras plataformas sin servidores como Cloud Functions y Cloud Run, o cualquier otra, si corresponde.

En este codelab, aprenderás a incluir y usar tareas de extracción de la lista de tareas en cola de App Engine en la app de ejemplo del codelab del módulo 1. Agregamos su uso de tareas de extracción en este instructivo del módulo 18 y, luego, migramos ese uso a Cloud Pub/Sub más adelante en el módulo 19. Aquellos que usen listas de tareas en cola para tareas push migrarán a Cloud Tasks en su lugar, por lo que deberán consultar los módulos 7-9.

En un próximo lab,

  • Usa la API o el servicio empaquetado de la lista de tareas en cola de App Engine
  • Agrega el uso de la lista de extracción a una app básica de Flask en App Engine NDB de Python 2.

Requisitos

Encuesta

¿Cómo usarás este instructivo?

Leer Leer y completar los ejercicios

¿Cómo calificarías tu experiencia en Python?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?

Principiante Intermedio Avanzado .
.

2. Información general

Para migrar desde las tareas de extracción de la lista de tareas en cola de App Engine, agrega su uso a la app existente de Flask y App Engine NBS que resulta del codelab del módulo 1. La app de ejemplo muestra las visitas más recientes al usuario final. No hay problema, pero es más interesante también hacer un seguimiento de los visitantes para ver quiénes tienen más visitas.

Si bien podríamos usar push Tasks para estos recuentos de visitantes, queremos dividir la responsabilidad entre la app de ejemplo cuyo trabajo es registrar visitas y responder de inmediato a los usuarios, y un "trabajador" designado. cuyo trabajo es contabilizar los recuentos de visitantes fuera del flujo de trabajo normal de solicitud-respuesta.

Para implementar este diseño, agregaremos el uso de listas de extracción a la aplicación principal y admitiremos la funcionalidad del trabajador. El trabajador puede ejecutarse como un proceso separado (como una instancia de backend o un código que se ejecuta en una VM que siempre está activa), un trabajo cron o una solicitud HTTP básica de línea de comandos con curl o wget. Después de esta integración, podrás migrar la app a Cloud Pub/Sub en el siguiente codelab (Módulo 19).

En este instructivo, se muestran los siguientes pasos:

  1. Configurar/trabajo previo
  2. Actualizar configuración
  3. Modifica el código de la aplicación

3. Configurar/trabajo previo

Esta sección explica cómo:

  1. Configura el proyecto de Cloud
  2. Obtén app de ejemplo del modelo de referencia
  3. (Re)Implementa y valida la app de referencia

Con estos pasos, te aseguras de comenzar a trabajar con código.

1. Configura el proyecto

Si completaste el codelab del módulo 1, vuelve a usar ese mismo proyecto (y código). Como alternativa, crea un proyecto completamente nuevo o reutiliza otro proyecto existente. Asegúrate de que el proyecto tenga una cuenta de facturación activa y una app de App Engine habilitada. Encuentra tu ID del proyecto, ya que lo necesitarás varias veces en este codelab y úsalo cuando encuentres la variable PROJECT_ID.

2. Obtén app de ejemplo del modelo de referencia

Uno de los requisitos previos para este codelab es tener una app de App Engine del Módulo 1 que funcione. Completa el codelab del módulo 1 (recomendado) o copia la app del módulo 1 del repositorio. Ya sea que uses el tuyo o el nuestro, comenzaremos en el código del módulo 1. En este codelab, se explica cada paso y se concluye con un código similar al que se encuentra en la carpeta del repositorio del módulo 18, “FINISH”.

Independientemente de la app del Módulo 1 que uses, la carpeta debería verse como el resultado a continuación, posiblemente con una carpeta lib:

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

3. (vuelve a) implementa la aplicación de modelo de referencia

Ejecuta los siguientes pasos para implementar la app del módulo 1:

  1. Borra la carpeta lib si hay una y ejecuta pip install -t lib -r requirements.txt para volver a propagar lib. Es posible que debas usar el comando pip2 en su lugar si tienes instalados Python 2 y 3.
  2. Asegúrate de haber instalado e inicializado la herramienta de línea de comandos de gcloud y de haber revisado su uso.
  3. Configura tu proyecto de Cloud con gcloud config set project PROJECT_ID si no quieres ingresar tu PROJECT_ID con cada comando gcloud emitido.
  4. Implementa la app de ejemplo con gcloud app deploy
  5. Confirma que la app del Módulo 1 se ejecute según lo esperado y muestre las visitas más recientes (como se ilustra a continuación).

a7a9d2b80d706a2b.png

4. Actualizar configuración

No es necesario realizar cambios en los archivos de configuración estándar de App Engine (app.yaml, requirements.txt, appengine_config.py). En su lugar, agrega un nuevo archivo de configuración, queue.yaml, con el siguiente contenido y colócalo en el mismo directorio de nivel superior:

queue:
- name: pullq
  mode: pull

El archivo queue.yaml especifica todas las listas de tareas en cola que existen para tu app (excepto la lista de aplicaciones en cola default, que App Engine crea automáticamente). En este caso, solo hay una, una lista de extracción llamada pullq. App Engine requiere que la directiva mode se especifique como pull; de lo contrario, crea una lista de aplicaciones en cola de forma predeterminada. Obtén más información sobre cómo crear listas de extracción en la documentación. Consulta también la página de referencia de queue.yaml para ver otras opciones.

Implementa este archivo por separado de tu app. Seguirás usando gcloud app deploy, pero también proporcionarás queue.yaml en la línea de comandos:

$ gcloud app deploy queue.yaml
Configurations to update:

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

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

Do you want to continue (Y/n)?

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

Task queues have been updated.

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

5. Modifica el código de la aplicación

En esta sección, se incluyen actualizaciones de los siguientes archivos:

  • main.py: Agrega el uso de listas de extracción a la aplicación principal.
  • templates/index.html: Actualiza la plantilla web para mostrar los datos nuevos.

Importaciones y constantes

El primer paso es agregar una importación nueva y varias constantes para admitir listas de extracción:

  • Agrega una importación de la biblioteca de lista de tareas en cola, google.appengine.api.taskqueue.
  • Agrega tres constantes para admitir liberar la cantidad máxima de tareas de extracción (TASKS) durante una hora (HOUR) desde nuestra lista de extracción (QUEUE).
  • Agregar una constante para mostrar las visitas más recientes y los visitantes principales (LIMIT).

A continuación, se muestra el código original y cómo se verá después de realizar estas actualizaciones:

ANTES:

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

app = Flask(__name__)

DESPUÉS:

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

Agregar una tarea de extracción (recopilar datos para la tarea y crear una tarea en la lista de extracción)

El modelo de datos Visit sigue siendo el mismo, al igual que las consultas de visitas para mostrar en fetch_visits(). El único cambio necesario en esta parte del código está en store_visit(). Además de registrar la visita, agrega una tarea a la lista de extracción con la dirección IP del visitante para que este pueda aumentar el contador de visitantes.

ANTES:

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

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

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

DESPUÉ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'
    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)

Crea un modelo de datos y una función de consulta para el seguimiento de visitantes

Agrega un modelo de datos VisitorCount para hacer un seguimiento de los visitantes. debe tener campos para el visitor y un counter entero para hacer un seguimiento de la cantidad de visitas. Luego, agrega una nueva función (alternativamente, puede ser un classmethod de Python) llamada fetch_counts() para buscar y mostrar a los visitantes principales en el orden de mayor a menor. Agrega la clase y la función justo debajo del cuerpo de fetch_visits():

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

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

Agregar código de trabajador

Agrega una nueva función log_visitors() para registrar visitantes a través de una solicitud GET a /log. Usa un diccionario o hash para hacer un seguimiento de los recuentos de visitantes más recientes, lo que permite asignar tantas tareas como sea posible durante una hora. Para cada tarea, cuenta todas las visitas del mismo visitante. Con los recuentos a mano, la app actualiza todas las entidades VisitorCount correspondientes que ya están en Datastore o crea nuevas si es necesario. El último paso devuelve un mensaje de texto sin formato que indica cuántos visitantes se registraron a partir de la cantidad de tareas procesadas. Agrega esta función a main.py justo debajo de fetch_counts():

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

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

Actualiza el controlador principal con nuevos datos de visualización

Para mostrar los visitantes principales, actualiza el controlador principal root() para invocar a fetch_counts(). Además, la plantilla se actualizará para mostrar el número de visitantes principales y de las visitas más recientes. Empaqueta el recuento de visitantes junto con las visitas más recientes de la llamada a fetch_visits() y agrégalos a un solo context para pasarlo a la plantilla web. A continuación, se muestran los códigos anteriores y posteriores a este cambio:

ANTES:

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

DESPUÉS:

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

Estos son todos los cambios necesarios para main.py. A continuación, se incluye una representación ilustrativa de esas actualizaciones con fines ilustrativos para que tengas una idea general de los cambios que realizarás en main.py:

ad5fd3345efc13d0.png

Actualizar plantilla web con nuevos datos de visualización

La plantilla web templates/index.html requiere una actualización para mostrar los visitantes principales, además de la carga útil normal de los visitantes más recientes. Suelta los visitantes principales y los recuentos en una tabla en la parte superior de la página y continúa procesando las visitas más recientes como antes. El único cambio adicional consiste en especificar el número que se muestra con la variable limit en lugar de codificarlo. Estas son las actualizaciones que debes realizar en tu plantilla web:

ANTES:

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

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

DESPUÉS:

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

<h1>VisitMe example</h1>

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

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

Con esto, se concluye los cambios necesarios para agregar el uso de tareas de extracción de la lista de tareas en cola de App Engine a la app de ejemplo del módulo 1. Tu directorio ahora representa la app de ejemplo del módulo 18 y debería contener los siguientes archivos:

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

6. Resumen/limpieza

En esta sección, se finaliza este codelab implementando la app y verificando que funcione según lo previsto y en cualquier resultado reflejado. Ejecuta el trabajador por separado para procesar el recuento de visitantes. Después de validar la app, realiza los pasos de limpieza y considera los siguientes.

Implementa y verifica la aplicación

Asegúrate de haber configurado tu lista de extracción como lo hicimos cerca de la parte superior de este codelab con gcloud app deploy queue.yaml. Si el proceso se completó y tu app de ejemplo está lista, implementa la app con gcloud app deploy. El resultado debería ser idéntico al de la app del Módulo 1, excepto que ahora presenta los "visitantes principales". en la parte superior:

b667551dcbab1a09.png

Si bien el frontend web actualizado muestra los visitantes principales y las visitas más recientes, tenga en cuenta que los recuentos de visitantes no incluyen esta visita. La app muestra el recuento de visitantes anteriores mientras descarta una tarea nueva, lo que aumenta el recuento de este visitante en la lista de extracción, una tarea que está a la espera de ser procesada.

Puedes ejecutar la tarea llamando a /log de varias maneras:

Por ejemplo, si usas curl para enviar una solicitud GET a /log, tu resultado se verá de la siguiente manera, si proporcionas tu PROJECT_ID:

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

El recuento actualizado se reflejará en la próxima visita al sitio web. Eso es todo.

Felicitaciones por completar este codelab para agregar correctamente el uso del servicio de lista de extracción de la lista de tareas en cola de App Engine a la app de ejemplo. Ya está listo para migrar a Cloud Pub/Sub, Cloud NDB y Python 3 en el módulo 19.

Limpia

General

Si ya terminaste, te recomendamos que inhabilites la aplicación de App Engine para evitar que se te facture. Sin embargo, si deseas probar o experimentar un poco más, la plataforma de App Engine tiene una cuota gratuita y, siempre y cuando no superes ese nivel de uso, no se te debería cobrar. Eso es para procesamiento, pero es posible que también se apliquen cargos por servicios relevantes de App Engine, así que consulta la página de precios para obtener más información. Si esta migración implica otros servicios de Cloud, estos se facturan por separado. En ambos casos, si corresponde, consulta la sección "Específico de este codelab" a continuación.

Para una divulgación completa, la implementación en una plataforma de procesamiento sin servidores de Google Cloud, como App Engine, genera costos menores de compilación y almacenamiento. Cloud Build tiene su propia cuota gratuita, al igual que Cloud Storage. El almacenamiento de esa imagen ocupa parte de esa cuota. Sin embargo, es posible que vivas en una región que no cuenta con ese nivel gratuito, así que ten en cuenta el uso que haces del almacenamiento para minimizar posibles costos. “Carpetas” específicas de Cloud Storage que debes revisar incluyen

  • 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
  • Los vínculos de almacenamiento anteriores dependen de tu PROJECT_ID y *LOC*; por ejemplo, "us" si tu app está alojada en EE.UU.

Por otro lado, si no vas a continuar con esta aplicación o algún otro codelab de migración relacionado y quieres borrar todo por completo, cierra tu proyecto.

Información específica de este codelab

Los servicios que se indican a continuación son exclusivos de este codelab. Consulta la documentación de cada producto para obtener más información:

Próximos pasos

En esta "migración", Agregaste el uso de la lista de aplicaciones en cola de la lista de tareas en cola a la app de ejemplo del Módulo 1. Para ello, agregaste compatibilidad con el seguimiento de visitantes y, por lo tanto, implementaste la app de ejemplo del Módulo 18. En la próxima migración, actualizarás las tareas de extracción de App Engine a Cloud Pub/Sub. Desde finales de 2021, los usuarios ya no tendrán la obligación de migrar a Cloud Pub/Sub cuando actualicen a Python 3. Obtén más información sobre este tema en la siguiente sección.

Para migrar a Cloud Pub/Sub, consulta el codelab del módulo 19. Además de eso, hay migraciones adicionales que se deben considerar, como Cloud Datastore, Cloud Memorystore, Cloud Storage o Cloud Tasks (listas de aplicaciones en cola). También hay migraciones de productos cruzados a Cloud Run y Cloud Functions. Se puede acceder a todo el contenido de Serverless Migration Station (codelabs, videos, código fuente [si está disponible]) en su repositorio de código abierto.

7. Migración a Python 3

En otoño de 2021, el equipo de App Engine amplió la compatibilidad de muchos de los servicios en paquetes a entornos de ejecución de 2a generación (que tienen un entorno de ejecución de 1a generación). Como resultado, ya no tienes que migrar de servicios agrupados, como la lista de tareas en cola de App Engine, a servicios de Cloud independientes o de terceros, como Cloud Pub/Sub, cuando migras tu aplicación a Python 3. En otras palabras, puedes seguir usando la lista de tareas en cola en las aplicaciones de Python 3 de App Engine, siempre y cuando actualices el código para acceder a servicios en paquetes desde entornos de ejecución de nueva generación.

Puedes obtener más información para migrar el uso de servicios agrupados a Python 3 en el codelab del módulo 17 y el video correspondiente. Si bien ese tema está fuera del alcance del módulo 18, en los vínculos que aparecen a continuación, se encuentran las versiones de Python 3 de la app del módulo 1 transferidas a Python 3 y aún usan App Engine NBS. (En algún momento, también estará disponible una versión de Python 3 de la app del Módulo 18).

8. Recursos adicionales

A continuación, se incluyen recursos adicionales para los desarrolladores que exploran este módulo o uno relacionado, así como productos relacionados. Esto incluye lugares donde enviar comentarios sobre este contenido, vínculos al código y varios documentos que pueden resultarte útiles.

Problemas o comentarios sobre el codelab

Si encuentras algún problema con este Codelab, primero busca el problema antes de enviarlo. Vínculos para buscar y crear problemas nuevos:

Recursos de migración

En la siguiente tabla, encontrarás los vínculos a las carpetas del repositorio del Módulo 1 (COMENZAR) y Módulo 18 (FINALIZAR). También se puede acceder a ellas desde el repositorio de todas las migraciones del codelab de App Engine. clonarlo o descargar un archivo ZIP.

Codelab

Python 2

Python 3

Módulo 1

código

code (no se incluye en este instructivo)

Módulo 18 (este codelab)

código

N/A

Referencias en línea

A continuación, hay recursos relevantes para este instructivo:

Lista de tareas en cola de App Engine

Plataforma de App Engine

Documentación de App Engine

Entorno de ejecución de App Engine (entorno estándar) para Python 2

Entorno de ejecución de App Engine (entorno estándar) para Python 3

Diferencias entre Python 2 y 3 entornos de ejecución de App Engine (entorno estándar)

Guía de migración de Python 2 a 3 de App Engine (entorno estándar)

Información de precios y cuotas de App Engine

Lanzamiento de la plataforma de App Engine de segunda generación (2018)

Asistencia a largo plazo para entornos de ejecución heredados

Ejemplos de migración de documentación

Otra información de Cloud

Videos

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.