Crear tareas de salida

En esta página se describe cómo crear tareas y colocarlas en colas de salida. Cuando quieras procesar una tarea, debes crear un objeto de tarea y colocarlo en una cola. Puedes especificar de forma explícita el servicio y el controlador que procesan la tarea, así como enviar datos específicos de la tarea al controlador (opcional). También puedes ajustar la configuración de la tarea, como programar una hora en el futuro para que se ejecute o limitar el número de veces que quieres que se vuelva a intentar si falla.

Crear una tarea

Para crear y poner en cola una tarea, llama a la función taskqueue.add(). El siguiente código crea una tarea que tiene como destino el servicio llamado worker e invoca su controlador definiendo la URL /update-counter:

class EnqueueTaskHandler(webapp2.RequestHandler):
    def post(self):
        amount = int(self.request.get('amount'))

        task = taskqueue.add(
            url='/update_counter',
            target='worker',
            params={'amount': amount})

        self.response.write(
            'Task {} enqueued, ETA {}.'.format(task.name, task.eta))

También puedes crear un objeto Task y llamar a su método add().

Especificar el servicio de trabajador

Cuando se extrae una tarea de su cola, el servicio de colas de tareas la envía a un servicio de trabajador. Cada tarea tiene un destino y una URL, que determinan qué servicio y controlador realizarán la tarea en última instancia.

target

El destino especifica el servicio que recibirá la solicitud HTTP para realizar la tarea. Es una cadena que especifica un servicio, una versión o una instancia en cualquiera de los formatos canónicos. Los formularios que se usan con más frecuencia son los siguientes:

    service
    version.service
    instance.version.service

La cadena de destino se añade al principio del nombre de dominio de tu aplicación. Hay tres formas de definir el destino de una tarea:

  • Declara el destino al crear la tarea. Puedes definir el destino explícitamente mediante el parámetro target en la función taskqueue.add(). Consulte el ejemplo anterior.

  • Incluye una directiva target cuando definas una cola en queue.yaml, como en la definición de queue-blue. Todas las tareas añadidas a una cola con un target usarán ese objetivo, aunque se haya asignado otro objetivo a la tarea en el momento de la creación.

  • Si no se especifica ningún destino según ninguno de los dos métodos anteriores, el destino de la tarea es la versión del servicio que la pone en cola. Ten en cuenta que, si pones en cola una tarea del servicio y la versión predeterminados de esta forma, y la versión predeterminada cambia antes de que se ejecute la tarea, se ejecutará en la nueva versión predeterminada.

url

url selecciona uno de los controladores del servicio de destino, que realizará la tarea.

El url debe coincidir con uno de los patrones de URL del controlador del servicio de destino. El url puede incluir parámetros de consulta si el método especificado en la tarea es GET o PULL. Si no se especifica ningún url, se usa la URL predeterminada /_ah/queue/[QUEUE_NAME], donde [QUEUE_NAME] es el nombre de la cola de la tarea.

Transferir datos al controlador

Puede transferir datos al controlador como parámetros de consulta en la URL de la tarea, pero solo si el método especificado en la tarea es GET o PULL.

También puedes usar cualquiera de los siguientes campos para añadir datos a una tarea:

  • payload, que envía los datos de la tarea en el cuerpo de la solicitud HTTP.
  • params

Estas tres llamadas son equivalentes:

taskqueue.add(method=GET, url='/update-counter?key=blue', target='worker')
taskqueue.add(url='/update-counter', params={'key': 'blue'}, target='worker')
taskqueue.add(url='/update-counter', payload="{'key': 'blue'}", target='worker')

Poner nombre a una tarea

Cuando creas una tarea, App Engine le asigna un nombre único de forma predeterminada. Sin embargo, puedes asignar tu propio nombre a una tarea usando el parámetro name. Una de las ventajas de asignar tus propios nombres a las tareas es que las tareas con nombre no se duplican, lo que significa que puedes usar nombres de tareas para garantizar que una tarea solo se añada una vez. La desduplicación continúa durante 9 días después de que se complete o se elimine la tarea.

Tenga en cuenta que la lógica de desduplicación introduce una sobrecarga de rendimiento significativa, lo que provoca un aumento de la latencia y, posiblemente, de las tasas de error asociadas a las tareas con nombre. Estos costes pueden aumentar significativamente si los nombres de las tareas son secuenciales, como ocurre con las marcas de tiempo. Por lo tanto, si asignas tus propios nombres, te recomendamos que utilices un prefijo bien distribuido para los nombres de las tareas, como un hash del contenido.

Si asignas tus propios nombres a las tareas, ten en cuenta que la longitud máxima del nombre es de 500 caracteres y que puede contener letras mayúsculas y minúsculas, números, guiones bajos y guiones.

taskqueue.add(url='/url/path', name='first-try')

Agregar tareas asincrónicamente

De forma predeterminada, las llamadas que añaden tareas a las colas son síncronas. En la mayoría de los casos, las llamadas síncronas funcionan correctamente. Añadir una tarea a una cola suele ser una operación rápida. Un pequeño porcentaje de las operaciones de añadir tareas pueden tardar mucho más, pero el tiempo medio para añadir una tarea es inferior a 5 ms.

Las operaciones de adición de tareas a diferentes colas no se pueden agrupar, por lo que la API Task Queue también proporciona llamadas asíncronas que te permiten añadir estas tareas en paralelo, lo que reduce aún más esta latencia. Esto resulta útil si estás creando una aplicación extremadamente sensible a la latencia que necesita realizar varias operaciones de adición de tareas a diferentes colas al mismo tiempo.

Si quieres hacer llamadas asíncronas a una cola de tareas, usa los métodos asíncronos que proporciona la clase Queue y un objeto RPC. Llama a get_result() en el objeto RPC devuelto para forzar que se complete la solicitud. Cuando añadas tareas de forma asíncrona en una transacción, debes llamar a get_result() en el objeto RPC antes de confirmar la transacción para asegurarte de que la solicitud se ha completado.

Poner tareas en cola en transacciones de Cloud Datastore

Puedes poner en cola una tarea como parte de una transacción de Datastore, de forma que la tarea solo se ponga en cola (y se garantice que se ponga en cola) si la transacción se confirma correctamente. Las tareas añadidas en una transacción se consideran parte de ella y tienen el mismo nivel de aislamiento y coherencia.

Una aplicación no puede insertar más de cinco tareas transaccionales en colas de tareas durante una sola transacción. Las tareas de transacción no deben tener nombres especificados por el usuario.

En el siguiente ejemplo de código se muestra cómo insertar tareas transaccionales en una cola de inserción como parte de una transacción de Datastore:

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

@ndb.transactional
def do_something_in_transaction():
  taskqueue.add(url='/path/to/my/worker', transactional=True)
  #...

do_something_in_transaction()

Usar la biblioteca de tareas diferidas en lugar de un servicio de trabajador

Configurar un controlador para cada tarea distinta (como se describe en las secciones anteriores) puede ser engorroso, al igual que serializar y deserializar argumentos complejos para la tarea, sobre todo si tienes muchas tareas diversas pero pequeñas que quieres ejecutar en la cola. El SDK de Python incluye una biblioteca (google.appengine.ext.deferred) que expone una función sencilla que te permite evitar todo el trabajo de configurar controladores de tareas específicos y serializar y deserializar tus parámetros.

Para usar esta biblioteca, debes añadir el elemento integrado deferred a app.yaml. Para obtener más información, consulta la sección Gestores integrados de la referencia de app.yaml.

Para usar la biblioteca deferred, solo tienes que pasar la función y sus argumentos a deferred.defer():

import logging

from google.appengine.ext import deferred

def do_something_expensive(a, b, c=None):
    logging.info("Doing something expensive!")
    # Do your work here

# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, True)

La biblioteca deferred empaqueta la llamada a la función y sus argumentos, y, a continuación, la añade a la cola de tareas. Cuando se ejecuta la tarea, la biblioteca deferred ejecuta do_something_expensive("Hello, world!", 42, True).

Trabajar con tareas en una aplicación multicliente

De forma predeterminada, las colas de inserción usan el espacio de nombres actual tal como se define en el gestor de espacios de nombres en el momento en que se crea la tarea. Si tu aplicación usa multitenencia, consulta la API Namespaces de Python 2.

Siguientes pasos