Programación asíncrona - AWS SDK para Java 1.x

AWS SDK para Java 1.x ha entrado en modo de mantenimiento el 31 de julio de 2024 y llegará al final de soporte el 31 de diciembre de 2025. Le recomendamos que migre a AWS SDK for Java 2.x para seguir recibiendo nuevas características, mejoras de disponibilidad y actualizaciones de seguridad.

Programación asíncrona

Puede utilizar métodos síncronos o asíncronos para llamar a operaciones en servicios de AWS. Los métodos síncronos bloquean la ejecución de los subprocesos hasta que el cliente recibe una respuesta del servicio. Los métodos asíncronos terminan de ejecutarse inmediatamente, devolviendo el control al subproceso que realiza la llamada sin esperar una respuesta.

Como un método asíncrono termina de ejecutarse antes de que haya una respuesta disponible, necesita una forma de obtener la respuesta cuando esté lista. AWS SDK para Java proporciona dos formas: objetos Future y métodos de devolución de llamada.

Objetos Future de Java

Los métodos asíncronos de AWS SDK para Java devuelven un objeto Future que contiene los resultados de la operación asíncrona en el futuro.

Llame al método Future isDone() para saber si el servicio ya ha proporcionado un objeto de respuesta. Cuando la respuesta esté lista, podrá obtener el objeto de respuesta llamando al método Future get(). Puede utilizar este mecanismo para sondear periódicamente los resultados de las operaciones asíncronas mientras su aplicación sigue trabajando en otras cosas.

A continuación se muestra un ejemplo de una operación asíncrona que llama a una función Lambda que recibe un objeto Future que puede contener un objeto InvokeResult. El objeto InvokeResult solo se recupera cuando isDone() es true.

import com.amazonaws.services.lambda.AWSLambdaAsyncClient; import com.amazonaws.services.lambda.model.InvokeRequest; import com.amazonaws.services.lambda.model.InvokeResult; import java.nio.ByteBuffer; import java.util.concurrent.Future; import java.util.concurrent.ExecutionException; public class InvokeLambdaFunctionAsync { public static void main(String[] args) { String function_name = "HelloFunction"; String function_input = "{\"who\":\"SDK for Java\"}"; AWSLambdaAsync lambda = AWSLambdaAsyncClientBuilder.defaultClient(); InvokeRequest req = new InvokeRequest() .withFunctionName(function_name) .withPayload(ByteBuffer.wrap(function_input.getBytes())); Future<InvokeResult> future_res = lambda.invokeAsync(req); System.out.print("Waiting for future"); while (future_res.isDone() == false) { System.out.print("."); try { Thread.sleep(1000); } catch (InterruptedException e) { System.err.println("\nThread.sleep() was interrupted!"); System.exit(1); } } try { InvokeResult res = future_res.get(); if (res.getStatusCode() == 200) { System.out.println("\nLambda function returned:"); ByteBuffer response_payload = res.getPayload(); System.out.println(new String(response_payload.array())); } else { System.out.format("Received a non-OK response from {AWS}: %d\n", res.getStatusCode()); } } catch (InterruptedException | ExecutionException e) { System.err.println(e.getMessage()); System.exit(1); } System.exit(0); } }

Devoluciones de llamadas asíncronas

Además de utilizar el objeto Future de Java para monitorizar el estado de las solicitudes asíncronas, el SDK también le permite implementar una clase que utilice la interfaz AsyncHandler. AsyncHandler proporciona dos métodos a los que se llama en función de cómo se haya completado la solicitud: onSuccess y onError.

La principal ventaja del enfoque de la interfaz de devolución de llamada es que se le permite sondear el objeto Future para saber si la solicitud se ha completado. El código puede iniciar inmediatamente su siguiente actividad y usar el SDK para llamar a su identificador en el momento oportuno.

import com.amazonaws.services.lambda.AWSLambdaAsync; import com.amazonaws.services.lambda.AWSLambdaAsyncClientBuilder; import com.amazonaws.services.lambda.model.InvokeRequest; import com.amazonaws.services.lambda.model.InvokeResult; import com.amazonaws.handlers.AsyncHandler; import java.nio.ByteBuffer; import java.util.concurrent.Future; public class InvokeLambdaFunctionCallback { private class AsyncLambdaHandler implements AsyncHandler<InvokeRequest, InvokeResult> { public void onSuccess(InvokeRequest req, InvokeResult res) { System.out.println("\nLambda function returned:"); ByteBuffer response_payload = res.getPayload(); System.out.println(new String(response_payload.array())); System.exit(0); } public void onError(Exception e) { System.out.println(e.getMessage()); System.exit(1); } } public static void main(String[] args) { String function_name = "HelloFunction"; String function_input = "{\"who\":\"SDK for Java\"}"; AWSLambdaAsync lambda = AWSLambdaAsyncClientBuilder.defaultClient(); InvokeRequest req = new InvokeRequest() .withFunctionName(function_name) .withPayload(ByteBuffer.wrap(function_input.getBytes())); Future<InvokeResult> future_res = lambda.invokeAsync(req, new AsyncLambdaHandler()); System.out.print("Waiting for async callback"); while (!future_res.isDone() && !future_res.isCancelled()) { // perform some other tasks... try { Thread.sleep(1000); } catch (InterruptedException e) { System.err.println("Thread.sleep() was interrupted!"); System.exit(0); } System.out.print("."); } } }

Prácticas recomendadas

Ejecución de la devolución de llamada

Su implementación de AsyncHandler se ejecuta dentro del grupo de subprocesos propiedad del cliente asíncrono. El código breve que se ejecuta rápidamente es más apropiado para su implementación de AsyncHandler. El código de bloqueo o de ejecución prolongada de sus métodos de identificador puede provocar controversia en el grupo de subprocesos usado por el cliente asíncrono y pueden impedir que el cliente ejecute las solicitudes. Si tiene una tarea de ejecución prolongada que debe iniciarse desde una devolución de llamada, permita que la devolución de llamada ejecute su tarea en un nuevo subproceso o en un grupo de subprocesos administrado por su aplicación.

Configuración del grupo de subprocesos

Los clientes asíncronos de AWS SDK para Java proporcionan un grupo de subprocesos predeterminado que debería funcionar para la mayoría de las aplicaciones. Puede implementar un ExecutorService personalizado y pasarlo a los clientes asíncronos de AWS SDK para Java para tener más control sobre cómo se administran los grupos de subprocesos.

Por ejemplo, puede proporcionar una implementación de ExecutorService que utilice un ThreadFactory personalizado para controlar la forma en que se asigna un nombre al grupo o para registrar información adicional sobre el uso de subprocesos.

Acceso asíncrono

La clase TransferManager del SDK ofrece soporte asíncrono para trabajar con Amazon S3. TransferManager administra las cargas y descargas asíncronas, proporciona informes detallados sobre el progreso de las transferencias y permite devoluciones de llamadas en diferentes eventos.