Manipulador de função do AWS Lambda em Java - AWS Lambda

Manipulador de função do AWS Lambda em Java

O manipulador da sua função do Lambda é o método no código da função que processa eventos. Quando sua função é invocada, o Lambda executa o método do manipulador. Quando o manipulador é encerrado ou retorna uma resposta, ele se torna disponível para tratar de outro evento.

No exemplo a seguir, uma classe chamada Handler define um método do manipulador chamado handleRequest. O método do manipulador usa um evento e um objeto de contexto como entrada e retorna uma string.

exemplo Handler.java

package example; import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.RequestHandler import com.amazonaws.services.lambda.runtime.LambdaLogger ... // Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public String handleRequest(Map<String,String> event, Context context) { LambdaLogger logger = context.getLogger(); String response = new String("200 OK"); // log execution details logger.log("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); logger.log("CONTEXT: " + gson.toJson(context)); // process event logger.log("EVENT: " + gson.toJson(event)); logger.log("EVENT TYPE: " + event.getClass().toString()); return response; } }

O tempo de execução do Lambda recebe um evento como uma string no formato JSON e o converte em um objeto. Ele transmite o objeto de evento ao manipulador de função juntamente com um objeto de contexto que fornece detalhes sobre a invocação e a função. Você indica ao tempo de execução qual método invocar definindo o parâmetro do manipulador na configuração da sua função.

Formatos do manipulador

  • package.Class::method – formato completo. Por exemplo: example.Handler::handleRequest.

  • package.Class – formato abreviado para funções que implantam uma interface do manipulador. Por exemplo: example.Handler.

É possível adicionar o código de inicialização fora do método do manipulador para reutilizar recursos em várias invocações. Quando o tempo de execução carrega seu manipulador, ele executa o código estático e o construtor de classe. Os recursos criados durante a inicialização permanecem na memória entre as invocações e podem ser reutilizados pelo manipulador milhares de vezes.

No exemplo a seguir, o logger, o serializador e o cliente do AWS SDK são criados quando a função atende seu primeiro evento. Eventos subsequentes atendidos pela mesma instância de função são muito mais rápidos porque esses recursos já existem.

exemplo Handler.java – código de inicialização

// Handler value: example.Handler public class Handler implements RequestHandler<SQSEvent, String>{ private static final Logger logger = LoggerFactory.getLogger(Handler.class); private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private static final LambdaAsyncClient lambdaClient = LambdaAsyncClient.create(); ... @Override public String handleRequest(SQSEvent event, Context context) { String response = new String(); // call Lambda API logger.info("Getting account settings"); CompletableFuture<GetAccountSettingsResponse> accountSettings = lambdaClient.getAccountSettings(GetAccountSettingsRequest.builder().build()); // log execution details logger.info("ENVIRONMENT VARIABLES: " + gson.toJson(System.getenv())); ...

O repositório do GitHub para este guia fornece aplicativos de exemplo fáceis de implantar que demonstram uma variedade de tipos de manipuladores. Para obter detalhes, consulte o final deste tópico.

Escolher tipos de entrada e saída

Especifique o tipo de objeto para o qual o evento é mapeado na assinatura do método do manipulador. No exemplo anterior, o tempo de execução do Java desserializa o evento em um tipo que implementa a interface Map<String,String>. Mapas de string a string funcionam para eventos simples como o seguinte:

exemplo Event.json – dados climáticos

{ "temperatureK": 281, "windKmh": -3, "humidityPct": 0.55, "pressureHPa": 1020 }

No entanto, o valor de cada campo deve ser uma string ou um número. Se o evento incluir um campo que tenha um objeto como um valor, o tempo de execução não poderá desserializá-lo e retornará um erro.

Escolha um tipo de entrada que funcione com os dados de evento que sua função processa. É possível usar um tipo básico, um tipo genérico ou um tipo bem definido.

Tipos de entrada

  • Integer, Long, Double etc. – o evento é um número sem formatação adicional, por exemplo, 3.5. O tempo de execução converte o valor em um objeto do tipo especificado.

  • String – o evento é uma string JSON, incluindo aspas, por exemplo, "My string.". O tempo de execução converte o valor (sem aspas) em um objeto String.

  • Type, Map<String,Type> etc. – o evento é um objeto JSON. O tempo de execução o desserializa em um objeto da interface ou tipo especificado.

  • List<Integer>, List<String>, List<Object> etc. – o evento é uma matriz JSON. O tempo de execução o desserializa em um objeto da interface ou tipo especificado.

  • InputStream – o evento é qualquer tipo JSON. O tempo de execução transmite um fluxo de bytes do documento ao manipulador sem modificação. Desserialize a entrada e grave a saída em um fluxo de saída.

  • Tipo de biblioteca – para eventos enviados pelos serviços da AWS, use os tipos na biblioteca aws-lambda-java-events.

Se você definir seu próprio tipo de entrada, ele deve ser um objeto Java simples e antigo (POJO) desserializável e mutável, com um construtor padrão e propriedades para cada campo no evento. Chaves no evento que não mapeiem para uma propriedade e propriedades que não estejam incluídas no evento são descartadas sem erro.

O tipo de saída pode ser um objeto ou void. O tempo de execução serializa valores de retorno em texto. Se a saída for um objeto com campos, o tempo de execução serializa-o em um documento JSON. Se for um tipo que envolve um valor primitivo, o tempo de execução retornará uma representação de texto desse valor.

Interfaces do manipulador

A biblioteca aws-lambda-java-core define duas interfaces para métodos do manipulador. Use as interfaces fornecidas para simplificar a configuração do manipulador e validar a assinatura do método do manipulador no momento da compilação.

A interface RequestHandler é um tipo genérico que usa dois parâmetros: o tipo de entrada e o tipo de saída. Ambos os tipos devem ser objetos. Quando você usa essa interface, o tempo de execução Java desserializa o evento em um objeto com o tipo de entrada e serializa a saída em texto. Use essa interface quando a serialização interna funcionar com seus tipos de entrada e saída.

exemplo Handler.java – interface do manipulador

// Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String>{ @Override public String handleRequest(Map<String,String> event, Context context)

Para usar sua própria serialização, implemente a interface RequestStreamHandler. Com essa interface, o Lambda transmite ao seu manipulador um fluxo de entrada e um fluxo de saída. O manipulador lê bytes do fluxo de entrada, grava no fluxo de saída e retorna um void.

O exemplo a seguir usa tipos de leitor e gravador em buffer para trabalhar com os fluxos de entrada e saída. Ele usa a biblioteca Gson para serialização e desserialização.

exemplo HandlerStream.java

import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.RequestStreamHandler import com.amazonaws.services.lambda.runtime.LambdaLogger ... // Handler value: example.HandlerStream public class HandlerStream implements RequestStreamHandler { Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { LambdaLogger logger = context.getLogger(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("US-ASCII"))); PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream, Charset.forName("US-ASCII")))); try { HashMap event = gson.fromJson(reader, HashMap.class); logger.log("STREAM TYPE: " + inputStream.getClass().toString()); logger.log("EVENT TYPE: " + event.getClass().toString()); writer.write(gson.toJson(event)); if (writer.checkError()) { logger.log("WARNING: Writer encountered an error."); } } catch (IllegalStateException | JsonSyntaxException exception) { logger.log(exception.toString()); } finally { reader.close(); writer.close(); } } }

Código de exemplo do manipulador

O repositório do GitHub para este guia inclui aplicativos de exemplo que demonstram o uso de vários tipos e interfaces de manipuladores. Cada aplicativo de exemplo inclui scripts para fácil implantação e limpeza, um modelo do AWS SAM e recursos de suporte.

Aplicativos de exemplo do Lambda em Java

  • blank-java – uma função Java que mostra o uso das bibliotecas Java do Lambda, registro em log, variáveis de ambiente, camadas, rastreamento do AWS X-Ray, testes de unidade e do AWS SDK.

  • java-basic – uma função Java mínima com testes de unidade e configuração de registro em log variável.

  • java-events – uma função Java mínima que usa a biblioteca aws-lambda-java-events com tipos de evento que não exigem o AWS SDK como dependência, como o Amazon API Gateway.

  • java-events-v1sdk – uma função Java que usa a biblioteca aws-lambda-java-events com tipos de evento que exigem o AWS SDK como dependência (Amazon Simple Storage Service, Amazon DynamoDB e Amazon Kinesis).

  • s3-java – uma função Java que processa eventos de notificação do Amazon S3 e usa a Java Class Library (JCL) para criar miniaturas de arquivos de imagem enviados por upload.

Os aplicativos s3-java e blank-java usam um evento de serviço da AWS como entrada e retornam uma string. O aplicativo java-basic inclui vários tipos de manipuladores:

Para testar diferentes tipos de manipuladores, basta alterar o valor do manipulador no modelo do AWS SAM. Para obter instruções detalhadas, consulte o arquivo readme do aplicativo de exemplo.