O blog da AWS

Construindo aplicações Serverless com Rust no AWS Lambda

Por Julian Wood, Principal Developer Advocate Amazon Web Services e Darko Mesaros, Principal Developer Advocate Amazon Web Services.

Hoje, o AWS Lambda está promovendo o suporte ao Rust de Experimental para Disponível Geralmente (GA). Isso significa que você agora pode usar Rust para construir aplicações Serverless críticas para o negócio, com suporte do AWS Support e o SLA de disponibilidade do Lambda.

Rust é uma linguagem de programação popular devido à sua combinação de alto desempenho, segurança de memória e experiência do desenvolvedor. Ela oferece velocidade e eficiência de utilização de memória comparáveis ao C++, juntamente com a confiabilidade normalmente associada a linguagens de nível mais alto.

Esta publicação mostra como construir e implantar funções Lambda baseadas em Rust usando Cargo Lambda, uma ferramenta de código aberto de terceiros para trabalhar com funções Lambda em Rust. Também abordaremos como implantar suas funções usando o construto Cargo Lambda AWS Cloud Development Kit (AWS CDK).

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Uma conta AWS com permissões apropriadas.
  • A Interface de Linha de Comando da AWS (AWS CLI) configurada com suas credenciais
  • Rust instalado em sua máquina de desenvolvimento (versão 1.70 ou posterior)
  • Node.js 20 ou posterior (para implantação do AWS CDK)
  • AWS CDK instalado: npm install -g aws-cdk

Visão geral da solução

Esta publicação guia você através das seguintes etapas:

  1. Instalar e configurar o Cargo Lambda.
  2. Criar e implantar uma função Lambda HTTP básica usando Cargo Lambda.
  3. Construir uma API Serverless completa usando AWS CDK com funções Lambda em Rust.

Instalar e configurar o Cargo Lambda

Cargo é o gerenciador de pacotes e sistema de compilação para Rust. Cargo Lambda é uma extensão de código aberto de terceiros para a ferramenta de linha de comando cargo que simplifica a construção e implantação de funções Lambda em Rust.

Para instalar o Cargo Lambda em sistemas Linux, execute:

curl -fsSL https://cargo-lambda.info/install.sh | sh
Code

Para opções adicionais de instalação, consulte a documentação de instalação do Cargo Lambda.

Criando sua primeira função Lambda em Rust

Crie uma função Lambda baseada em HTTP:

cargo lambda new hi_api
Code

Quando solicitado Is this function an HTTP function?, digite y.

cd hi_api
Code

Isso cria um projeto com a seguinte estrutura:

├── Cargo.toml
├── README.md
└── src
    ├── http_handler.rs
    └── main.rs
Code

O projeto inclui:

  • main.rs – O ponto de entrada da função onde você configura dependências e estado compartilhado
  • http_handler.rs – A lógica principal da função

O arquivo main.rs contém o seguinte código:

use lambda_http::{run, service_fn, tracing, Error};
mod http_handler;
use http_handler::function_handler;
#[tokio::main]
async fn main() -> Result<(), Error> {
tracing::init_default_subscriber();
run(service_fn(function_handler)).await
}
Code

A parte chave do arquivo main.rs é run(service_fn(function_handler)).await. A função run faz parte do crate http_lambda e inicia o cliente de interface de runtime (RIC) do Lambda Rust, que pesquisa ativamente por eventos da API de Runtime do Lambda. O function_handler é a função definida no arquivo http_handler.rs. Quando a API de Runtime retorna o evento de invocação, o RIC chama o function_handler de http_handler.rs:

use lambda_http::{Body, Error, Request, RequestExt, Response};
pub(crate) async fn function_handler(event: Request) -> Result<Response, Error> {
// Extract some useful information from the request
let who = event
.query_string_parameters_ref()
.and_then(|params| params.first("name"))
.unwrap_or("world");
let message = format!("Hello {who}, this is an AWS Lambda HTTP request");
// Return something that implements IntoResponse.
// It will be serialized to the right response event automatically by the runtime

let resp = Response::builder()
    .status(200)
    .header("content-type", "text/html")
    .body(message.into())
    .map_err(Box::new)?;
Ok(resp)

}
Code

A assinatura da função function_handler inclui uma variável event do tipo Request. O conteúdo de event depende do serviço que está acionando a função. Por exemplo, pode conter informações de solicitação HTTP, como parâmetros de caminho, se a solicitação estiver vindo via HTTP, ou até mesmo um array de registros de stream do Amazon Kinesis.

Para funções não HTTP, os eventos podem ser fortemente tipados. Além disso, você pode aceitar qualquer estrutura como entrada, desde que ela implemente serde::Serialize e serde::Deserialize.

O exemplo analisa parâmetros de consulta e procura o primeiro parâmetro que tem o nome name.

O crate lambda_http fornece uma maneira idiomática de retornar uma resposta, usando um padrão de construtor. A função retorna uma resposta como um Result com um Ok(), que é o que a função run em main.rs espera.

Registro de logs

O arquivo main.rs inclui a seguinte linha por padrão:

tracing::init_default_subscriber();
Code

O runtime do Lambda Rust integra-se nativamente com bibliotecas Tracing para registro e rastreamento, e suporta registro estruturado JSON. Ao definir esta linha e a variável de ambiente RUST_LOG, o Lambda envia logs para o Amazon CloudWatch. Por padrão, o nível de log INFO está habilitado.

Para escrever logs, use o crate tracing e envie eventos usando a seguinte sintaxe:

tracing::info("This is a log entry");
Code

Compilação

Para compilar a função Lambda, use cargo lambda build. Ao compilar a função Lambda, o AWS Lambda Runtime é incorporado ao seu binário. O arquivo binário compilado é chamado bootstrap. Ele é empacotado no arquivo .zip do artefato da função e visível como um arquivo no console do AWS Lambda.

Quando o Lambda executa este binário, ele inicia um loop infinito (a função Run). Isso pesquisa a API de Runtime do Lambda para receber a solicitação de invocação e então chama seu manipulador, a função function_handler.

O código da sua função é executado e então envia a resposta da função de volta para a API de Runtime do Lambda, que a encaminha para o chamador.

Testes

Antes de implantar a função, você pode depurar/testar a função localmente usando cargo lambda.

cargo lambda watch configura um ambiente que emula o ambiente de execução do Lambda. Isso permite que você envie solicitações para a função Lambda e veja os resultados.

Para enviar solicitações de invocação, você pode usar cargo lambda ou enviar uma solicitação curl para o emulador do Lambda.

Para usar cargo lambda, execute o seguinte, substitua <lambda-function-name> por hi_api para este exemplo

cargo lambda invoke <lambda-function-name> --data-example apigw-request
Code

Você pode usar qualquer um dos payloads de exemplo integrados com o parâmetro --data-example. Use --data-ascii <payload> para fornecer seu próprio payload.

Para invocar a função usando curl, passe o payload em formato JSON para o endereço do emulador local:

curl -v -X POST \
  'http://127.0.0.1:9000/lambda-url/<lambda-function-name>/' \
  -H 'content-type: application/json' \
  -d '{ "command": "hi" }'
Code

Implantando com Cargo Lambda

Depois de compilar a função usando cargo lambda build, você pode implantá-la em sua conta AWS.

Para implantar sua função:

cargo lambda deploy
Code

Depois que a função Lambda for implantada, você pode testá-la remotamente. cargo lambda invoke testa a função Lambda remota usando um payload armazenado em um arquivo .json:

cargo lambda invoke --remote hi_api --data-file <event file>
Code

Infraestrutura como Código com AWS CDK

Você pode criar uma API Serverless na frente desta função Lambda em Rust usando o Amazon API Gateway. Este exemplo usa o AWS CDK. Este exemplo não tem autenticação configurada para o endpoint do API Gateway, pois é uma exemplo. A melhor prática da AWS é implementar controles de segurança relevantes quando necessário.

  1. Primeiro, crie um novo projeto CDK:
mkdir rusty_cdk
cd rusty_cdk
cdk init --language=typescript
Shell

A maneira mais fácil de implantar uma função Lambda em Rust usando o AWS CDK é usar o Construto CDK do cargo lambda. Ele vem com tudo o que é necessário para executar funções Lambda em Rust na AWS. Faz parte do projeto cargo lambda.

2. Instale o construto CDK do Cargo Lambda:

npm i cargo-lambda-cdk
Shell

3. Crie uma nova função Lambda HTTP em seu projeto:

mkdir lambda
cd lambda
cargo lambda new helloRust
Shell

Quando solicitado Is this function an HTTP function?, digite y.

4. Atualize sua pilha CDK lib/rusty_cdk-stack.ts para incluir tanto a função Lambda quanto o API Gateway.

import * as cdk from 'aws-cdk-lib';
import { HttpApi } from 'aws-cdk-lib/aws-apigatewayv2';
import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
import { HttpMethod } from 'aws-cdk-lib/aws-events';
import { RustFunction } from 'cargo-lambda-cdk';
import { Construct } from 'constructs';
export class RustyCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    const helloRust = new RustFunction(this, 'helloRust',{
      manifestPath: './lambda/helloRust',
      runtime: 'provided.al2023',
      timeout: cdk.Duration.seconds(30),
    });

    const api = new HttpApi(this, 'rustyApi');
    const helloInteg = new HttpLambdaIntegration('helloInteg', helloRust);

    api.addRoutes({
      path: '/hello',
      methods: [HttpMethod.GET],
      integration: helloInteg,
    })
    new cdk.CfnOutput(this, 'apiUrl',{
      description: 'The URL of the API Gateway',
      value: `https://${api.apiId}.execute-api.${this.region}.amazonaws.com`,
    })
  }
}
JavaScript

5. Inicialize sua conta AWS e Região da AWS para o AWS CDK:

cdk bootstrap
Shell

6. Implante sua pilha:

cdk deploy
Shell

Testando a API

Para testar sua API implantada usando a URL fornecida na saída do AWS CDK:

curl https://<YOUR_API_URL>/hello
Shell

Limpeza

Para evitar cobranças contínuas, remova os recursos implantados:

cdk destroy
Shell

Conclusão

O suporte do AWS Lambda para Rust está agora Disponível Geralmente para construir aplicações Serverless de alto desempenho e eficiência de memória. Cargo Lambda é uma extensão de terceiros para a CLI cargo do Rust que simplifica a experiência de desenvolver, testar e implantar aplicações Rust no Lambda.

Para saber mais sobre a construção de aplicações Serverless com Rust:

Para encontrar mais exemplos de código em Rust, use a Coleção de Padrões Serverless. Para mais recursos de aprendizado Serverless, visite Serverless Land.

Este conteúdo foi traduzido do post original do blog, que pode ser encontrado aqui.

Autores

Julian Wood é um Principal Developer Advocate Amazon Web Services
Darko Mesaros é um Principal Developer Advocate Amazon Web Services

Tradutores

Daniel Abib é Arquiteto de Soluções Sênior e Especialista em Amazon Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/

.

Rodrigo Peres é Arquiteto de Soluções na AWS, com mais de 20 anos de experiência trabalhando com arquitetura de soluções, desenvolvimento de sistemas e modernização de sistemas legados.