Crea tareas de aplicaciones en cola

En esta página, se describe cómo crear tareas y colocarlas en listas de aplicaciones en cola. Cuando desees procesar una tarea, debes crear un objeto de tarea nuevo y colocarlo en una cola. Puedes especificar explícitamente el servicio y el controlador que procesarán la tarea y, de manera opcional, transferir los datos específicos de la tarea al controlador. También puedes ajustar la configuración de la tarea, como programar una hora en el futuro en la que se debe ejecutar o limitar la cantidad de veces que deseas que se reintente la tarea si falla.

Crear una tarea nueva

Para crear una tarea y colocarla en cola, obtén una Queue con QueueFactory y llama a su método add(). Puedes obtener una cola nombrada especificada en el archivo queue.xml usando el método getQueue() de la fábrica, o puedes obtener la cola predeterminada con getDefaultQueue(). Puedes llamar al método add() de la Queue con una instancia de TaskOptions producida por TaskOptions.Builder o puedes llamarlo sin argumentos a fin de crear una tarea con las opciones predeterminadas para la cola.

Java 8

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/worker").param("key", key));

Java 7


import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/worker").param("key", key));

Cómo especificar el servicio de trabajador

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

target

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

    service
    version.service
    instance.version.service

La string de destino se antepone al nombre del dominio de tu aplicación. Existen tres maneras de establecer el destino para una tarea:

  • Declarar el destino cuando construyes la tarea. Puedes configurar el destino de manera explícita cuando creas la tarea estableciendo el encabezado Host con TaskOptions:

    taskOptions.header("Host", versionHostname)
    

  • Incluir una directiva target cuando defines una cola en queue.xml, como en la definición de queue-blue. Todas las tareas agregadas a una cola con target usarán ese destino, incluso si se asignó un destino diferente a la tarea durante el tiempo de construcción.

  • Si no se especifica ningún destino según los dos métodos descritos anteriormente, el destino de la tarea será 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 manera, y la versión predeterminada cambia antes de que la tarea se ejecute, esta se ejecutará en la versión predeterminada nueva.

url

La url selecciona uno de los controladores en el servicio de destino, el cual realizará la tarea.

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

Transferir datos al controlador

Puedes pasar 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.

El constructor TaskOptions.Builder tiene métodos para agregar datos como carga útil de la solicitud HTTP, además de como parámetros, que se agregan a la URL como parámetros de consulta.

params
No especifiques los parámetros si utilizas el método POST junto con una carga útil, o si utilizas el método GET y agregaste una URL con parámetros de consulta.

Cómo nombrar una tarea

Cuando creas una tarea nueva, App Engine le asigna un nombre único de manera predeterminada. Sin embargo, puedes asignarles tus propios nombres a las tareas con el parámetro name. Una de las ventajas de asignar tus propios nombres a las tareas es que las tareas nombradas se deduplican, lo que significa que puedes usar nombres de tareas para garantizar que una tara se agregue solo una vez. La deduplicación se mantiene durante 9 días después de que se completa o se borra una tarea.

Ten en cuenta que la lógica de deduplicación ingresa una sobrecarga de rendimiento significativa, lo que se traduce en mayores latencias y mayor potencial de tasas de error asociadas con las tareas nombradas. Estos costos pueden aumentar significativamente si los nombres de las tareas son secuenciales, como 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 tareas, como un hash de los contenidos.

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

Agregar tareas de manera asíncrona

De manera predeterminada, las llamadas que agregan tareas a las colas son síncronas. Las llamadas síncronas funcionan bien en la mayoría de los casos. Agregar una tarea a una cola es generalmente una operación rápida. Existe un pequeño porcentaje de operaciones de agregado de tareas que pueden tardar mucho más tiempo, pero el tiempo medio para agregar una tarea es inferior a 5 minutos.

Las operaciones de agregado de tareas a diferentes colas no se pueden agrupar, por lo que la API de listas de tareas en cola también proporciona llamadas asíncronas que te permiten agregar estas tareas en paralelo, minimizando aún más esta latencia. Esto es útil si estás creando una aplicación extremadamente sensible a la latencia que necesita realizar varias operaciones de agregación de tareas a diferentes colas al mismo tiempo.

Si deseas realizar llamadas asíncronas a una lista de tareas en cola, utiliza los métodos asíncronos proporcionados por la clase Cola. Llama a get en el Future que se muestra para forzar que se complete la solicitud. Cuando agregues tareas de manera asíncrona en una transacción, debes llamar a get() en Future antes de confirmar la transacción para asegurarte de que la solicitud haya finalizado.

Cómo poner en cola tareas en transacciones de Cloud Datastore

Puedes poner una tarea en cola como parte de una transacción de Cloud Datastore, de manera que la tarea solo se pone en cola (y se garantiza que está en cola) si la transacción se confirma correctamente. Las tareas que se agregan a 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 las listas de tareas en cola durante una sola transacción. Las tareas transaccionales no deben tener nombres especificados por el usuario.

El siguiente código de muestra indica cómo insertar tareas transaccionales en una lista de aplicaciones en cola como parte de una transacción de Cloud Datastore:

DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Queue queue = QueueFactory.getDefaultQueue();
try {
    Transaction txn = ds.beginTransaction();

    // ...

    queue.add(TaskOptions.Builder.withUrl("/path/to/my/worker"));

    // ...
    txn.commit();
} catch (DatastoreFailureException e) {
}

Cómo usar DeferredTasks en lugar de un servicio de trabajador

La configuración de un controlador para cada tarea distinta (como se describe en las secciones anteriores) puede ser complicada, al igual que la serialización y deserialización de argumentos complejos para la tarea, en especial si tienes muchas tareas diferentes pero pequeñas que deseas ejecutar en la cola. El SDK de Java incluye una interfaz llamada DeferredTask. Esta interfaz te permite definir una tarea como un método único. Utiliza la serialización de Java para empaquetar una unidad de trabajo en una lista de tareas en cola. Un retorno simple de ese método se considera un éxito. Si se muestra cualquier excepción desde ese método, la operación se considera un fracaso.

Java 8


/** A hypothetical expensive operation we want to defer on a background task. */
public static class ExpensiveOperation implements DeferredTask {

  @Override
  public void run() {
    System.out.println("Doing an expensive operation...");
    // expensive operation to be backgrounded goes here
  }
}

/**
 * Basic demonstration of adding a deferred task.
 *
 * @param request servlet request
 * @param resp servlet response
 */
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse resp)
    throws IOException {
  // Add the task to the default queue.
  Queue queue = QueueFactory.getDefaultQueue();

  // Wait 5 seconds to run for demonstration purposes
  queue.add(
      TaskOptions.Builder.withPayload(new ExpensiveOperation())
          .etaMillis(System.currentTimeMillis() + DELAY_MS));

  resp.setContentType("text/plain");
  resp.getWriter().println("Task is backgrounded on queue!");
}

Java 7

/**
 * A hypothetical expensive operation we want to defer on a background task.
 */
public static class ExpensiveOperation implements DeferredTask {
  @Override
  public void run() {
    System.out.println("Doing an expensive operation...");
    // expensive operation to be backgrounded goes here
  }
}

/**
 * Basic demonstration of adding a deferred task.
 * @param request servlet request
 * @param resp servlet response
 */
@Override
public void doGet(final HttpServletRequest request,
    final HttpServletResponse resp) throws IOException {
  // Add the task to the default queue.
  Queue queue = QueueFactory.getDefaultQueue();

  // Wait 5 seconds to run for demonstration purposes
  queue.add(TaskOptions.Builder.withPayload(new ExpensiveOperation())
      .etaMillis(System.currentTimeMillis() + DELAY_MS));

  resp.setContentType("text/plain");
  resp.getWriter().println("Task is backgrounded on queue!");
}

Cómo trabajar con tareas en una aplicación de varias instancias

De manera predeterminada, las listas de aplicaciones en cola utilizan el espacio de nombres actual como se establece en el administrador de espacio de nombres en el momento en que se crea la tarea. Si tu aplicación es multiusuario, consulta la API de Java 8 de espacios de nombres.

Pasos siguientes

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java 8