Definir o manipulador de função do Lambda em Rust
nota
O cliente runtime do Rust
O manipulador da 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. A função é executada até que o manipulador retorne uma resposta, seja encerrado ou atinja o tempo limite.
Tópicos
Conceitos básicos do handler em Rust
Escreva seu código de função do Lambda como um executável Rust. Implemente o código da função do manipulador e uma função principal e inclua o seguinte:
-
A caixa lambda_runtime
de crates.io, que implementa o modelo de programação Lambda para Rust. -
Inclua Tokio
em suas dependências. O cliente de runtime Rust para Lambda usa o Tokio para lidar com chamadas assíncronas.
exemplo — Manipulador do Rust que processa eventos JSON
O exemplo a seguir usa a caixa serde_json
use lambda_runtime::{service_fn, LambdaEvent, Error}; use serde_json::{json, Value}; async fn handler(event: LambdaEvent<Value>) -> Result<Value, Error> { let payload = event.payload; let first_name = payload["firstName"].as_str().unwrap_or("world"); Ok(json!({ "message": format!("Hello, {first_name}!") })) } #[tokio::main] async fn main() -> Result<(), Error> { lambda_runtime::run(service_fn(handler)).await }
Observe o seguinte:
-
use
: importa as bibliotecas que sua função do Lambda exige. -
async fn main
: o ponto de entrada que executa o código da função do Lambda. O cliente de runtime Rust usa o Tokiocomo um runtime assíncrono, de modo que você precisa anotar a função principal com #[tokio::main]
. -
async fn handler(event: LambdaEvent<Value>) -> Result<Value,
Error
>
: esta é a assinatura do manipulador do Lambda. Ele inclui o código que será executado quando a função for chamada.-
LambdaEvent<Value>
: este é um tipo genérico que descreve o evento recebido pelo runtime do Lambda, bem como o contexto da função Lambda. -
Result<Value, Error>
: a função retorna um tipoResult
. Se a função tiver êxito, o resultado será um valor JSON. Se a função não tiver êxito, o resultado será um erro.
-
Uso de estado compartilhado
É possível declarar e modificar variáveis globais que são independentes do código do manipulador da função do Lambda. Essas variáveis podem ajudá-lo a carregar informações de estado durante o Fase de inicialização, antes que sua função receba qualquer evento.
exemplo — Compartilhe o cliente Amazon S3 em todas as instâncias da função
Observe o seguinte:
-
use aws_sdk_s3::Client
: este exemplo exige que você adicioneaws-sdk-s3 = "0.26.0"
à lista de dependências em seu arquivoCargo.toml
. -
aws_config::from_env
: este exemplo exige que você adicioneaws-config = "0.55.1"
à lista de dependências em seu arquivoCargo.toml
.
use aws_sdk_s3::Client; use lambda_runtime::{service_fn, Error, LambdaEvent}; use serde::{Deserialize, Serialize}; #[derive(Deserialize)] struct Request { bucket: String, } #[derive(Serialize)] struct Response { keys: Vec<String>, } async fn handler(client: &Client, event: LambdaEvent<Request>) -> Result<Response, Error> { let bucket = event.payload.bucket; let objects = client.list_objects_v2().bucket(bucket).send().await?; let keys = objects .contents() .map(|s| s.iter().flat_map(|o| o.key().map(String::from)).collect()) .unwrap_or_default(); Ok(Response { keys }) } #[tokio::main] async fn main() -> Result<(), Error> { let shared_config = aws_config::from_env().load().await; let client = Client::new(&shared_config); let shared_client = &client; lambda_runtime::run(service_fn(move |event: LambdaEvent<Request>| async move { handler(&shared_client, event).await })) .await }
Práticas recomendadas de código para as funções do Lambda em Rust
Adote as diretrizes da lista a seguir para usar as práticas recomendadas de codificação ao compilar suas funções do Lambda:
-
Separe o manipulador do Lambda da lógica central. Isso permite que você crie uma função mais fácil para teste de unidade.
-
Minimize a complexidade de suas dependências. Prefira frameworks mais simples que sejam carregados rapidamente no startup do ambiente de execução.
-
Minimize o tamanho do pacote de implantação às necessidades do runtime. Isso reduzirá a quantidade de tempo necessária para que seu pacote de implantação seja obtido por download e desempacotado antes da invocação.
-
Aproveite a reutilização do ambiente de execução para melhorar a performance da função. Inicialize clientes SDK e conexões de banco de dados fora do manipulador de funções e armazene em cache os ativos estáticos localmente no diretório
/tmp
. As invocações subsequentes processadas pela mesma instância da função podem reutilizar esses recursos. Isso economiza custos reduzindo o runtime da função.Para evitar possíveis vazamentos de dados entre invocações, não use o ambiente de execução para armazenar dados do usuário, eventos ou outras informações com implicações de segurança. Se sua função depende de um estado mutável que não pode ser armazenado na memória dentro do manipulador, considere criar uma função separada ou versões separadas de uma função para cada usuário.
-
Use uma diretiva de keep-alive para manter conexões persistentes. O Lambda limpa conexões ociosas ao longo do tempo. A tentativa de reutilizar uma conexão ociosa ao invocar uma função resultará em um erro de conexão. Para manter sua conexão persistente, use a diretiva keep-alive associada ao runtime. Para obter um exemplo, consulte Reutilizar conexões com keep-alive em Node.js.
-
Use variáveis de ambiente para passar parâmetros operacionais para sua função. Por exemplo, se estiver gravando em um bucket do Amazon S3, em vez fixar no código o nome do bucket em que você está gravando, configure o nome do bucket como uma variável de ambiente.
-
Evite usar código recursivo em sua função do Lambda, em que a função chame a si mesma automaticamente até que alguns critérios arbitrários sejam atendidos. Isso pode levar a um volume não intencional de invocações da função e a custos elevados. Se você fizer isso acidentalmente, defina a simultaneidade reservada da função como
0
imediatamente para limitar todas as invocações da função, enquanto você atualiza o código. -
Não use APIs não documentadas e não públicas no código da função Lambda. Para os tempos de execução gerenciados pelo AWS Lambda, o Lambda aplica periodicamente atualizações funcionais e de segurança às APIs internas do Lambda. Essas atualizações internas da API podem ser incompatíveis com versões anteriores, gerando consequências não intencionais, como falhas de invocação, caso sua função tenha dependência nessas APIs não públicas. Consulte a referência da API para obter uma lista de APIs disponíveis publicamente.
-
Escreva um código idempotente. Escrever um código idempotente para suas funções garante que eventos duplicados sejam tratados da mesma maneira. Seu código deve validar eventos adequadamente e lidar corretamente com eventos duplicados. Para obter mais informações, consulte Como torno minha função do Lambda idempotente?
.