Programação assíncrona - AWS SDK para Java 1.x

O AWS SDK para Java 1.x entrou no modo de manutenção em 31 de julho de 2024 e o fim do suporte está previsto para 31 de dezembro de 2025. Recomendamos que você migre para o AWS SDK for Java 2.x para continuar recebendo novos recursos, melhorias de disponibilidade e atualizações de segurança.

Programação assíncrona

Você pode usar os métodos síncronos ou assíncronos para chamar operações em serviços da AWS. 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. O AWS SDK para Java oferece duas maneiras: objetos Future e métodos de retorno de chamada.

Futures do Java

Os métodos assíncronos no AWS SDK para Java retornam um objeto Future que contém os resultados da operação assíncrona no futuro.

Chame o método Future isDone() para ver se o serviço já forneceu um objeto de resposta. Quando a resposta estiver pronta, você poderá obter o objeto de resposta chamando o método Future get(). É possível usar esse mecanismo para sondar periodicamente os resultados da operação assíncrona, enquanto o aplicativo continua funcionando em outras atividades.

Aqui está um exemplo de uma operação assíncrona que chama uma função Lambda recebendo um Future capaz de manter um objeto InvokeResult. O objeto InvokeResult será recuperado somente depois que isDone() for 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); } }

Retornos de chamada assíncronos

Além de usar o objeto do Java Future para monitorar o status de requisições assíncronas, o SDK também permite implementar uma classe que usa a interface AsyncHandler. AsyncHandler oferece dois métodos chamados de acordo com a maneira como a requisição foi concluída: onSuccess e onError.

A principal vantagem da interface da abordagem de interface do retorno de chamada é que ela evita a necessidade de sondar o objeto Future para descobrir quando a requisição foi concluída. Em vez disso, o código pode iniciar imediatamente a próxima atividade e contar com o SDK para chamar o handler no momento certo.

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áticas recomendadas

Execução do retorno de chamada

A implementação de AsyncHandler é executada dentro do grupo de threads de propriedade do cliente assíncrono. Resumidamente, o código executado rapidamente é mais apropriado dentro da implementação AsyncHandler. Executar por muito tempo ou bloquear código dentro dos métodos handler pode causar contenção do grupo de threads usado pelo cliente assíncrono e evitar que o cliente execute requisições. Se você tiver uma tarefa de longa duração que precise começar de um retorno de chamada, o retorno de chamada deverá executar a tarefa em um novo thread ou em um grupo de threads gerenciado pelo aplicativo.

Configuração do grupo de threads

Os clientes assíncronos no AWS SDK para Java oferecem um grupo de threads padrão que deve funcionar na maioria dos aplicativos. Você pode implementar um ExecutorService personalizado e passá-lo para clientes assíncronos do AWS SDK para Java a fim de obter mais controle sobre como os grupos de threads são gerenciados.

Por exemplo, você pode fornecer uma implementação ExecutorService que use um ThreadFactory personalizado para controlar a maneira como threads no grupo são nomeados ou para registrar em log informações adicionais sobre o uso de threads.

Processo assíncrono

A classe TransferManager no SDK oferece suporte assíncrono para trabalhar com o Amazon S3. O TransferManager gerencia uploads e downloads assíncronos, fornece relatórios de progresso detalhados sobre transferências e dá suporte a retornos de chamada em eventos diferentes.