Utiliser la programmation asynchrone - AWS SDK for Java 2.x

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Utiliser la programmation asynchrone

AWS SDK for Java 2.x Il propose des clients asynchrones avec un support d'E/S non bloquant qui implémentent une simultanéité élevée sur quelques threads. Cependant, l'absence totale de blocage des E/S n'est pas garantie. Le client asynchrone peut bloquer les appels dans certains cas, tels que la récupération des informations d'identification, la signature des demandes à l'aide de AWS Signature Version 4 (SigV4) ou la découverte des terminaux.

Les méthodes synchrones bloquent l'exécution du thread jusqu'à ce que le client reçoive une réponse du service. Les méthodes asynchrones renvoient immédiatement, en rendant le contrôle au thread appelant sans attendre de réponse.

Dans la mesure où une méthode asynchrone renvoie avant qu'une réponse ne soit disponible, vous avez besoin d'une solution pour obtenir la réponse quand elle est prête. Les méthodes pour le client asynchrone dans la version 2.x des CompletableFuture objets de AWS SDK for Java retour qui vous permettent d'accéder à la réponse lorsqu'elle est prête.

Utiliser un client asynchrone APIs

Les signatures des méthodes clientes asynchrones sont les mêmes que leurs homologues synchrones, mais les méthodes asynchrones renvoient un CompletableFutureobjet contenant les résultats de l'opération asynchrone à venir. Si une erreur est renvoyée pendant l'exécution SDK de la méthode asynchrone, l'erreur est renvoyée sous la forme. CompletionException

Une approche que vous pouvez utiliser pour obtenir le résultat consiste à enchaîner une whenComplete() méthode sur le résultat CompletableFuture renvoyé par l'appel de SDK méthode. La whenComplete() méthode reçoit le résultat ou un objet Throwable de type CompletionException dépendant de la façon dont l'appel asynchrone s'est terminé. Vous fournissez une action pour whenComplete() traiter ou vérifier les résultats avant qu'ils ne soient renvoyés au code d'appel.

Si vous souhaitez renvoyer autre chose que l'objet renvoyé par la SDK méthode, utilisez plutôt la handle() méthode. La handle() méthode prend les mêmes paramètres quewhenComplete(), mais vous pouvez traiter le résultat et renvoyer un objet.

Pour attendre la fin de la chaîne asynchrone et récupérer les résultats d'achèvement, vous pouvez appeler la join() méthode. Si l'Throwableobjet n'a pas été traité dans la chaîne, la join() méthode renvoie une valeur non cochée CompletionException qui enveloppe l'exception d'origine. Vous accédez à l'exception d'origine avecCompletionException#getCause(). Vous pouvez également appeler la CompletableFuture#get() méthode pour obtenir les résultats d'achèvement. La get() méthode peut toutefois générer des exceptions vérifiées.

L'exemple suivant montre deux variantes de la façon dont vous pouvez utiliser la listTables() méthode du client asynchrone DynamoDB. L'action passée à enregistre whenComplete() simplement une réponse réussie, tandis que la handle() version extrait la liste des noms de tables et renvoie la liste. Dans les deux cas, si une erreur est générée dans la chaîne asynchrone, l'erreur est renvoyée afin que le code client ait une chance de la gérer.

Importations

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;

Code

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; } }); } }

Gérez le streaming dans des méthodes asynchrones

Pour les méthodes asynchrones avec du contenu en streaming, vous devez fournir un AsyncRequestBodypour fournir le contenu de manière incrémentielle, ou un AsyncResponseTransformerpour recevoir et traiter la réponse.

L'exemple suivant télécharge un fichier de Amazon S3 manière asynchrone en utilisant la forme asynchrone de l'opération. PutObject

Importations

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;

Code

/** * 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(); } }

L'exemple suivant extrait un fichier à l'aide Amazon S3 de la forme asynchrone de l'GetObjectopération.

Importations

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;

Code

/** * 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(); } }

Configuration des options asynchrones avancées

La version AWS SDK for Java 2.x utilise Netty, un framework d'applications réseau asynchrone piloté par des événements, pour gérer les threads d'E/S. Le AWS SDK for Java 2.x crée un ExecutorService Behind Netty, pour compléter les contrats à terme renvoyés par la demande du HTTP client jusqu'au client Netty. Cette abstraction réduit le risque qu'une application interrompe le processus asynchrone si les développeurs choisissent d'arrêter ou de mettre des threads en veille. Par défaut, chaque client asynchrone crée un pool de threads basé sur le nombre de processeurs et gère les tâches d'une file d'attente au sein du. ExecutorService

Vous pouvez spécifier une JDK implémentation spécifique ExecutorService lors de la création de votre client asynchrone. L'extrait de code suivant crée un ExecutorService avec un nombre fixe de threads.

Code

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

Pour optimiser les performances, vous pouvez gérer votre propre exécuteur de pool de threads et l'inclure lorsque vous configurez votre client.

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();