JavaAsync

paul-manjarres edited this page Dec 13, 2012 · 3 revisions
Clone this wiki locally

Manejando resultados Asíncronos

Esta página todavía no ha sido traducida al castellano. Puedes ayudarnos con la tarea simplemente presionando el botón Edit Page. Para más información puedes leer esta guía para el traductor. Aquí puedes ver cuánto nos falta para terminar la traducción.

Por qué resultados Asíncronos?

Hasta ahora, eramos capaces de procesar el resultado para enviar al cliente web directamente. Esto no siempre es el caso: el resultado puede depender de un procesamiento costoso o una llamada a Web Service muy larga.

Debido a la forma en que Play 2.0 funciona, el código de acción debe ser lo más rápido posible (e.j. non-blocking). Así que, que se debería enviar como resultado si aún no hemos sido capaces de procesarlo? La respuesta debe ser una promesa de un resultado!

Una promesa de resultado Promise<Result> eventualmente será redimida con un valor de tipo Result. Al entregar un Promise<Result> en vez de un Result normal, somos capaces de procesar el resultado rápidamente sin bloquear nada. Play entonces entregará el resultado tan rápido como la promesa sea redimida.

El cliente web será bloqueado mientras espera por la respuesta pero nada será bloqueado en el servidor, y los recursos del servidor podrán ser usados para responder a otros clientes.

Como crear un Promise<Result>

Para crear un Promise<Result> necesitamos otra promesa primero: la promesa que nos dará el valor que debemos procesar:

Promise<Double> promiseOfPIValue = computePIAsynchronously();
Promise<Result> promiseOfResult = promiseOfPIValue.map(
  new Function<Double,Result>() {
    public Result apply(Double pi) {
      return ok("PI value computed: " + pi);
    } 
  }
);

Nota: Escribir composiciones funcionales en Java es bastante extenso (verbose) en estos momentos, pero debería mejorar cuando Java de soporte a notación lambda.

Los métodos asíncronos del API de Play 2.0 entregan un Promise. Este es el caso cuando se está invocando un Web Service externo usando el API play.libs.WS, o si está usando Akka para programar tareas asíncronas o para comunicarse con actores usando play.libs.Akka.

Una manera simple de ejecutar un bloque de código de manera asíncrona y obtener un Promise es usar los métodos utilitarios de play.libs.Akka:

Promise<Integer> promiseOfInt = Akka.future(
  new Callable<Integer>() {
    public Integer call() {
      intensiveComputation();
    }
  }
);

Nota: Aquí, el método de procesamiento intensivo se ejecutará en otro Thread. También es posible ejecutarlo remotamente en un cluster de servidores utilizando Akka remote.

AsyncResult

Mientras usábamos Results.Status hasta ahora, para enviar un resultado asíncrono debemos usar Results.AsyncResult que envuelva el resultado original:

public static Result index() {
  Promise<Integer> promiseOfInt = Akka.future(
    new Callable<Integer>() {
      public Integer call() {
        intensiveComputation();
      }
    }
  );
  async(
    promiseOfInt.map(
      new Function<Integer,Result>() {
        public Result apply(Integer i) {
          return ok("Got result: " + i);
        } 
      }
    )
  );
}

Nota: async() es un método utilitario que construye un AsyncResult a partir de un Promise<Result>.

Next: Streaming HTTP responses