Usar programação assíncrona - AWS SDK for Java 2.x

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Usar programação assíncrona

Ele AWS SDK for Java 2.x apresenta clientes assíncronos com suporte de E/S sem bloqueio que implementam alta simultaneidade em alguns segmentos. No entanto, a E/S total sem bloqueio não é garantida. O cliente assíncrono pode realizar chamadas de bloqueio em alguns casos, como recuperação de credenciais, assinatura de solicitações usando AWS Signature Version 4 (SigV4) ou descoberta de endpoints.

Os métodos síncronos bloqueiam a execução do seu thread até o cliente receber uma resposta do serviço. Os métodos assíncronos retornam imediatamente, devolvendo o controle ao thread de chamada sem aguardar uma resposta.

Como um método assíncrono retorna antes de uma resposta estar disponível, você precisa de uma maneira de obter a resposta quando ela estiver pronta. Os métodos para clientes assíncronos em 2.x dos CompletableFuture objetos de AWS SDK for Java retorno que permitem acessar a resposta quando ela estiver pronta.

Use um cliente assíncrono APIs

As assinaturas dos métodos assíncronos do cliente são as mesmas que as assinaturas síncronas, mas os métodos assíncronos retornam um CompletableFutureobjeto que contém os resultados da operação assíncrona no futuro. Se um erro for gerado durante a execução SDK do método assíncrono, o erro será lançado como. CompletionException

Uma abordagem que você pode usar para obter o resultado é encadear um whenComplete() método no CompletableFuture retornado pela chamada do SDK método. O whenComplete() método recebe o resultado ou um objeto Throwable do tipo, CompletionException dependendo de como a chamada assíncrona foi concluída. Você fornece uma ação whenComplete() para processar ou verificar os resultados antes que eles retornem ao código de chamada.

Se você quiser retornar algo diferente do objeto retornado pelo SDK método, use o handle() método em vez disso. O handle() método usa os mesmos parâmetros quewhenComplete(), mas você pode processar o resultado e retornar um objeto.

Para aguardar a conclusão da cadeia assíncrona e recuperar os resultados da conclusão, você pode chamar o método. join() Se o Throwable objeto não foi manipulado na cadeia, o join() método lança um não verificado CompletionException que envolve a exceção original. Você acessa a exceção original comCompletionException#getCause(). Você também pode chamar o CompletableFuture#get() método para obter os resultados da conclusão. O get() método, no entanto, pode gerar exceções verificadas.

O exemplo a seguir mostra duas variações de como você pode trabalhar com o listTables() método do cliente assíncrono do DynamoDB. A ação passada para whenComplete() simplesmente registra uma resposta bem-sucedida, enquanto a handle() versão extrai a lista de nomes de tabelas e retorna a lista. Em ambos os casos, se um erro for gerado na cadeia assíncrona, o erro será relançado para que o código do cliente tenha a chance de lidar com ele.

Importações

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; import java.util.List; import java.util.concurrent.CompletableFuture;

Código

whenComplete() variation
public class DynamoDbAsyncListTables { public static void main(String[] args) { Region region = Region.US_EAST_1; DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder().region(region).build(); try { ListTablesResponse listTablesResponse = listTablesWhenComplete(dynamoDbAsyncClient).join(); // The join() method may throw a CompletionException. if (listTablesResponse.hasTableNames()){ System.out.println("Table exist in this region: " + region.id()); } } catch (RuntimeException e) { // Handle as needed. Here we simply print out the class names. System.out.println(e.getClass()); // Prints 'class java.util.concurrent.CompletionException'. System.out.println(e.getCause().getClass()); // Prints 'class software.amazon.awssdk.services.dynamodb.model.DynamoDbException'. } } public static CompletableFuture<ListTablesResponse> listTablesWhenComplete(DynamoDbAsyncClient client) { return client.listTables(ListTablesRequest.builder().build()) .whenComplete((listTablesResponse, throwable) -> { if (listTablesResponse != null) { // Consume the response. System.out.println("The SDK's listTables method completed successfully."); } else { RuntimeException cause = (RuntimeException) throwable.getCause(); // If an error was thrown during the SDK's listTables method it is wrapped in a CompletionException. // The SDK throws only RuntimeExceptions, so this is a safe cast. System.out.println(cause.getMessage()); // Log error here, but rethrow so the calling code can handle as needed. throw cause; } }); }
handle() variation
public class DynamoDbAsyncListTables { public static void main(String[] args) { Region region = Region.US_EAST_1; DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder().region(region).build(); try { List<String> tableNames = listTablesHandle(dynamoDbAsyncClient).join(); // The join() method may throw a CompletionException. tableNames.forEach(System.out::println); } catch (RuntimeException e) { // Handle as needed. Here we simply print out the class names. System.out.println(e.getClass()); // Prints 'class java.util.concurrent.CompletionException'. System.out.println(e.getCause().getClass()); // Prints 'class software.amazon.awssdk.services.dynamodb.model.DynamoDbException'. } } public static CompletableFuture<List<String>> listTablesHandle(DynamoDbAsyncClient client) { return client.listTables(ListTablesRequest.builder().build()) .handle((listTablesResponse, throwable) -> { if (listTablesResponse != null) { return listTablesResponse.tableNames(); // Return the list of table names. } else { RuntimeException cause = (RuntimeException) throwable.getCause(); // If an error was thrown during the SDK's listTables method it is wrapped in a CompletionException. // The SDK throws only RuntimeExceptions, so this is a safe cast. System.out.println(cause.getMessage()); // Log error here, but rethrow so the calling code can handle as needed. throw cause; } }); } }

Gerencie o streaming em métodos assíncronos

Para métodos assíncronos com conteúdo de streaming, você deve fornecer um AsyncRequestBodypara fornecer o conteúdo de forma incremental ou um AsyncResponseTransformerpara receber e processar a resposta.

O exemplo a seguir carrega um arquivo de forma Amazon S3 assíncrona usando a forma assíncrona da operação. PutObject

Importações

import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

Código

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncOps <bucketName> <key> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " key - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String key = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(key) .build(); // Put the object into the bucket CompletableFuture<PutObjectResponse> future = client.putObject(objectRequest, AsyncRequestBody.fromFile(Paths.get(path)) ); future.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object uploaded. Details: " + resp); } else { // Handle error err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); future.join(); } }

O exemplo a seguir obtém um arquivo Amazon S3 usando a forma assíncrona da operação. GetObject

Importações

import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

Código

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncStreamOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncStreamOps <bucketName> <objectKey> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " objectKey - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String objectKey = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); GetObjectRequest objectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(objectKey) .build(); CompletableFuture<GetObjectResponse> futureGet = client.getObject(objectRequest, AsyncResponseTransformer.toFile(Paths.get(path))); futureGet.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object downloaded. Details: "+resp); } else { err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); futureGet.join(); } }

Configurar opções assíncronas avançadas

O AWS SDK for Java 2.x usa o Netty, uma estrutura assíncrona de aplicativos de rede orientada por eventos, para lidar com threads de E/S. O AWS SDK for Java 2.x cria um Netty ExecutorService por trás, para completar os futuros retornados da solicitação do HTTP cliente para o cliente Netty. Essa abstração reduz o risco de um aplicativo interromper o processo assíncrono se os desenvolvedores optarem por suspender ou desabilitar threads. Por padrão, cada cliente assíncrono cria um threadpool com base no número de processadores e gerencia as tarefas em uma fila dentro do ExecutorService.

Você pode especificar uma JDK implementação específica de ExecutorService quando você cria seu cliente assíncrono. O trecho a seguir cria um ExecutorService com um número fixo de linhas de execução.

Código

S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, Executors.newFixedThreadPool(10) ) ) .build();

Para otimizar o desempenho, você pode gerenciar seu próprio executor de pool de threads e incluí-lo ao configurar seu cliente.

ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(<custom_value>), new ThreadFactoryBuilder() .threadNamePrefix("sdk-async-response").build()); // Allow idle core threads to time out executor.allowCoreThreadTimeOut(true); S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, executor ) ) .build();