Definição dos manipuladores de função do Lambda em Go
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.
Esta página descreve como trabalhar com manipuladores de função do Lambda em Go, incluindo a configuração de projeto, as convenções de nomenclatura e as práticas recomendadas. Além disso, esta página apresenta um exemplo de uma função do Lambda em Go que aceita informações sobre um pedido, produz um recibo em formato de texto e armazena esse arquivo em um bucket do Amazon Simple Storage Service (S3). Para obter mais informações sobre como implantar a função após gravá-la, consulte Implantar funções do Lambda em Go com arquivos .zip ou Implantar funções do Lambda em Go com imagens de contêiner.
Tópicos
- Configuração do projeto de manipulador em Go
- Exemplo de código de função do Lambda em Go
- Convenções de nomenclatura para manipuladores
- Definição e acesso ao objeto do evento de entrada
- Acesso e uso do objeto de contexto do Lambda
- Assinaturas de manipulador válidas para manipuladores em Go
- Uso do AWS SDK for Go v2 em seu manipulador
- Acesso a variáveis de ambiente
- Usar o estado global
- Práticas recomendadas de código para as funções do Lambda em GO
Configuração do projeto de manipulador em Go
Uma função do Lambda escrita em Gogo mod init
:
go mod init
example-go
Neste caso, example-go
é o nome do módulo. Você pode substituí-lo por qualquer nome que desejar. Este comando inicializa seu projeto e gera o arquivo go.mod
, que lista as dependências do projeto.
Use o comando go get
para adicionar quaisquer dependências externas ao seu projeto. Por exemplo, para todas as funções do Lambda em Go, é necessário incluir o pacote github.com/aws/aws-lambda-go/lambdago get
:
go get github.com/aws/aws-lambda-go
O código da sua função deve estar em um arquivo em Go. No exemplo apresentado a seguir, chamamos esse arquivo de main.go
. Neste arquivo, você implementa a lógica principal da função em um método manipulador, bem como uma função main()
que chama esse manipulador.
Exemplo de código de função do Lambda em Go
O exemplo de código apresentado a seguir para uma função do Lambda em Go aceita informações sobre um pedido, produz um recibo em formato de texto e armazena esse arquivo em um bucket do Amazon S3.
exemplo Função do Lambda em main.go
package main import ( "context" "encoding/json" "fmt" "log" "os" "strings" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) type Order struct { OrderID string `json:"order_id"` Amount float64 `json:"amount"` Item string `json:"item"` } var ( s3Client *s3.Client ) func init() { // Initialize the S3 client outside of the handler, during the init phase cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatalf("unable to load SDK config, %v", err) } s3Client = s3.NewFromConfig(cfg) } func uploadReceiptToS3(ctx context.Context, bucketName, key, receiptContent string) error { _, err := s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &bucketName, Key: &key, Body: strings.NewReader(receiptContent), }) if err != nil { log.Printf("Failed to upload receipt to S3: %v", err) return err } return nil } func handleRequest(ctx context.Context, event json.RawMessage) error { // Parse the input event var order Order if err := json.Unmarshal(event, &order); err != nil { log.Printf("Failed to unmarshal event: %v", err) return err } // Access environment variables bucketName := os.Getenv("RECEIPT_BUCKET") if bucketName == "" { log.Printf("RECEIPT_BUCKET environment variable is not set") return fmt.Errorf("missing required environment variable RECEIPT_BUCKET") } // Create the receipt content and key destination receiptContent := fmt.Sprintf("OrderID: %s\nAmount: $%.2f\nItem: %s", order.OrderID, order.Amount, order.Item) key := "receipts/" + order.OrderID + ".txt" // Upload the receipt to S3 using the helper method if err := uploadReceiptToS3(ctx, bucketName, key, receiptContent); err != nil { return err } log.Printf("Successfully processed order %s and stored receipt in S3 bucket %s", order.OrderID, bucketName) return nil } func main() { lambda.Start(handleRequest) }
Este arquivo main.go
contém as seguintes seções de código:
-
package main
: na linguagem Go, o pacote que contém a funçãofunc main()
deve sempre ser nomeado comomain
. -
Bloco
import
: utilize este bloco para incluir as bibliotecas necessárias para a função do Lambda. -
Bloco
type Order struct {}
: define o formato do evento de entrada esperado nesta estrutura em Go. -
Bloco
var ()
: use este bloco para definir quaisquer variáveis globais que você usará na função do Lambda. -
func init() {}
: inclua qualquer código que você deseja que o Lambda execute durante a fase de inicialização neste métodoinit()
. -
func uploadReceiptToS3(...) {}
: este é um método auxiliar que é referenciado pelo método principal do manipuladorhandleRequest
. -
func handleRequest(ctx context.Context, event json.RawMessage) error {}
: este é o método principal do manipulador, que contém a lógica principal da sua aplicação. -
func main() {}
: este é um ponto de entrada obrigatório para seu manipulador do Lambda. O argumento para o métodolambda.Start()
corresponde ao seu método principal do manipulador.
Para que esta função funcione corretamente, seu perfil de execução deve permitir a ação s3:PutObject
. Além disso, certifique-se de definir a variável de ambiente RECEIPT_BUCKET
. Após uma invocação com êxito, o bucket do Amazon S3 deve conter um arquivo de recibo.
Convenções de nomenclatura para manipuladores
Para funções do Lambda em Go, você pode usar qualquer nome para o manipulador. Neste exemplo, o nome do método do manipulador é handleRequest
. Para referenciar o valor do manipulador em seu código, você pode usar a variável de ambiente _HANDLER
.
Para funções em Go implantadas usando um pacote de implantação .zip, o arquivo executável que contém o código da sua função deve ser nomeado bootstrap
. Além disso, o arquivo bootstrap
deve estar na raiz do arquivo .zip. Para funções em Go implantadas usando uma imagem de contêiner, é possível usar qualquer nome para o arquivo executável.
Definição e acesso ao objeto do evento de entrada
O formato de entrada JSON é o mais comum e padrão para funções do Lambda. Neste exemplo, a função espera uma entrada semelhante à seguinte:
{ "order_id": "12345", "amount": 199.99, "item": "Wireless Headphones" }
Ao trabalhar com funções do Lambda em Go, é possível definir o formato do evento de entrada esperado como uma estrutura em Go. Neste exemplo, definimos uma estrutura para representar um Order
:
type Order struct { OrderID string `json:"order_id"` Amount float64 `json:"amount"` Item string `json:"item"` }
Essa estrutura corresponde ao formato de entrada esperado. Após definir a estrutura, você pode gravar uma assinatura de manipulador que aceita um tipo JSON genérico compatível com a biblioteca padrão encoding/json
func handleRequest(ctx context.Context, event json.RawMessage) error { // Parse the input event var order Order if err := json.Unmarshal(event, &order); err != nil { log.Printf("Failed to unmarshal event: %v", err) return err ... }
Após a desserialização, é possível acessar os campos da variável order
. Por exemplo, order.OrderID
recupera o valor de "order_id"
da entrada original.
nota
O pacote encoding/json
tem acesso somente a campos que são exportados. Para serem exportados, os nomes do campo no struct do evento devem estar em letra maiúscula.
Acesso e uso do objeto de contexto do Lambda
O objeto de contexto do Lambda contém informações sobre a invocação, a função e o ambiente de execução. Neste exemplo, declaramos essa variável como ctx
na assinatura do manipulador:
func handleRequest(ctx context.Context, event json.RawMessage) error { ... }
A entrada ctx context.Context
é um argumento opcional em seu manipulador de função. Para obter mais informações sobre as assinaturas de manipulador aceitas, consulte Assinaturas de manipulador válidas para manipuladores em Go.
Se você realizar chamadas a outros serviços usando o AWS SDK, o objeto de contexto será necessário em algumas áreas importantes. Por exemplo, para inicializar corretamente os clientes do SDK, é possível carregar a configuração adequada do AWS SDK usando o objeto de contexto da seguinte maneira:
// Load AWS SDK configuration using the default credential provider chain cfg, err := config.LoadDefaultConfig(ctx)
As próprias chamadas do SDK podem exigir o objeto de contexto como um parâmetro de entrada. Por exemplo, a chamada s3Client.PutObject
aceita o objeto de contexto como seu primeiro argumento:
// Upload the receipt to S3 _, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ ... })
Além das solicitações do AWS SDK, é possível usar o objeto de contexto para realizar o monitoramento da função. Para obter mais informações sobre o objeto de contexto, consulte Usar o objeto de contexto do Lambda para recuperar informações das funções em Go.
Assinaturas de manipulador válidas para manipuladores em Go
Há várias opções ao criar um manipulador de função do Lambda no Go, mas você deve observar as seguintes regras:
-
O manipulador deve ser uma função.
-
O manipulador pode usar de 0 a 2 argumentos. Se houver dois argumentos, o primeiro argumento deverá implementar
context.Context
. -
O manipulador pode retornar de 0 a 2 argumentos. Se houver um único valor de retorno, ele deverá implementar
error
. Se houver dois valores de retorno, o segundo valor deverá implementarerror
.
As assinaturas válidas de manipulador são listadas a seguir. TIn
e TOut
representam tipos compatíveis com a biblioteca encoding/json padrão. Para obter mais informações, consulte func Unmarshal
-
func ()
-
func () error
-
func () (TOut, error)
-
func (TIn) error
-
func (TIn) (TOut, error)
-
func (context.Context) error
-
func (context.Context) (TOut, error)
-
func (context.Context, TIn) error
-
func (context.Context, TIn) (TOut, error)
Uso do AWS SDK for Go v2 em seu manipulador
Frequentemente, você usará as funções do Lambda para interagir com ou fazer atualizações em outros recursos da AWS. A maneira mais simples de interagir com esses recursos é usar o AWS SDK for Go v2.
nota
O AWS SDK for Go (v1) está em modo de manutenção e terá o suporte encerrado em 31 de julho de 2025. Recomendamos que você use somente o AWS SDK for Go v2 daqui em diante.
Para adicionar as dependências do SDK à sua função, use o comando go get
para os clientes específicos do SDK que você precisa. No código de exemplo anterior, usamos a biblioteca config
e a biblioteca s3
. Adicione essas dependências ao executar os seguintes comandos no diretório que contém seus arquivos go.mod
e main.go
:
go get github.com/aws/aws-sdk-go-v2/config go get github.com/aws/aws-sdk-go-v2/service/s3
Em seguida, importe as dependências correspondentes no bloco “import” da sua função:
import ( ... "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" )
Ao usar o SDK no seu manipulador, configure os clientes com as configurações adequadas. A maneira mais simples de fazer isso é usar a cadeia de provedores de credenciais padrão. Este exemplo ilustra uma forma de carregar essa configuração:
// Load AWS SDK configuration using the default credential provider chain cfg, err := config.LoadDefaultConfig(ctx) if err != nil { log.Printf("Failed to load AWS SDK config: %v", err) return err }
Após carregar essa configuração na variável cfg
, você pode fornecê-la nas instâncias dos clientes. No exemplo, o código cria uma instância de cliente do Amazon S3 da seguinte maneira:
// Create an S3 client s3Client := s3.NewFromConfig(cfg)
Neste exemplo, inicializamos nosso cliente do Amazon S3 na função init()
para evitar a necessidade de inicializá-lo a cada vez que nossa função é invocada. O problema é que, na função init()
, o Lambda não tem acesso ao objeto de contexto. Como solução alternativa, você pode fornecer um espaço reservado, como context.TODO()
, durante a fase de inicialização. Posteriormente, ao fazer uma chamada usando o cliente, forneça o objeto de contexto completo. Esta solução alternativa também é descrita em Uso do contexto nas inicializações e nas chamadas do cliente do AWS SDK.
Após configurar e inicializar o cliente do SDK, você pode usá-lo para interagir com outros serviços da AWS. O código de exemplo chama a API PutObject
do Amazon S3 da seguinte forma:
_, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &bucketName, Key: &key, Body: strings.NewReader(receiptContent), })
Acesso a variáveis de ambiente
No código do manipulador, você pode fazer referência a qualquer variável de ambiente ao usar o método os.Getenv()
. Neste exemplo, referenciamos a variável de ambiente RECEIPT_BUCKET
definida usando a seguinte linha de código:
// Access environment variables bucketName := os.Getenv("RECEIPT_BUCKET") if bucketName == "" { log.Printf("RECEIPT_BUCKET environment variable is not set") return fmt.Errorf("missing required environment variable RECEIPT_BUCKET") }
Usar o estado global
Para evitar a criação de novos recursos a cada vez que você invoca a função, é possível declarar e modificar variáveis globais externas ao código do manipulador da função do Lambda. Defina essas variáveis globais em um bloco ou em uma instrução em var
. Além disso, o manipulador pode declarar uma função init()
que é executada durante a fase de inicialização. No AWS Lambda, o método init
se comporta de maneira idêntica aos programas em Go padrão.
Práticas recomendadas de código para as funções do Lambda em GO
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 para conter somente o necessário para o 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 invocações recursivas em sua função do Lambda, em que a função invoca a si mesma ou inicia um processo que pode invocar a função novamente. Isso pode levar a um volume não intencional de invocações da função e a custos elevados. Se você observar um volume não intencional de invocações, defina a simultaneidade reservada da função como
0
imediatamente para limitar todas as invocações da função enquanto 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?
.