Python e AWS Lambda: Guia Serverless
Crie funcoes serverless com Python e AWS Lambda. Aprenda deploy, API Gateway, layers, testes locais e boas praticas de producao.
AWS Lambda revolucionou a forma como construimos aplicacoes na nuvem. Em vez de gerenciar servidores, voce escreve funcoes que executam sob demanda, pagando apenas pelo tempo de execucao. Python e uma das linguagens mais populares no Lambda, e neste guia vamos explorar como criar, testar e fazer deploy de funcoes serverless de forma profissional.
O Que e AWS Lambda
AWS Lambda e um servico de computacao serverless. Voce envia seu codigo, define um gatilho (HTTP, fila, agendamento) e a AWS cuida de toda a infraestrutura. Nao ha servidores para provisionar, escalar ou manter.
As principais vantagens sao: escalonamento automatico, cobranca por milissegundo de execucao, integracao nativa com outros servicos AWS e suporte a Python 3.12.
Sua Primeira Funcao Lambda
Uma funcao Lambda em Python e simples. Ela recebe um evento e um contexto:
import json
from datetime import datetime
def handler(event, context):
"""Funcao Lambda basica que retorna uma saudacao."""
nome = event.get("nome", "Mundo")
hora = datetime.now().strftime("%H:%M:%S")
resposta = {
"mensagem": f"Ola, {nome}! Sao {hora}.",
"funcao": context.function_name,
"memoria_mb": context.memory_limit_in_mb,
"request_id": context.aws_request_id,
}
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(resposta, ensure_ascii=False),
}
O parametro event contem os dados do gatilho (payload HTTP, mensagem da fila, etc). O context traz metadados da execucao, como nome da funcao, memoria disponivel e tempo restante.
Configurando com SAM (Serverless Application Model)
O AWS SAM simplifica o desenvolvimento local e o deploy de funcoes Lambda:
pip install aws-sam-cli
sam init --runtime python3.12 --name meu-projeto
O arquivo template.yaml define a infraestrutura:
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 30
MemorySize: 256
Runtime: python3.12
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.handler
CodeUri: src/
Events:
ApiEvent:
Type: Api
Properties:
Path: /saudacao
Method: get
ProcessarPedido:
Type: AWS::Serverless::Function
Properties:
Handler: pedidos.processar
CodeUri: src/
Events:
FilaSQS:
Type: SQS
Properties:
Queue: !GetAtt FilaPedidos.Arn
FilaPedidos:
Type: AWS::SQS::Queue
Properties:
QueueName: fila-pedidos
API REST com API Gateway
O caso de uso mais comum e expor funcoes Lambda como endpoints HTTP:
import json
import uuid
from datetime import datetime
# Simulando banco de dados em memoria
PRODUTOS = {}
def listar_produtos(event, context):
"""GET /produtos - Lista todos os produtos."""
produtos = list(PRODUTOS.values())
return {
"statusCode": 200,
"body": json.dumps({"produtos": produtos, "total": len(produtos)}),
}
def criar_produto(event, context):
"""POST /produtos - Cria um novo produto."""
try:
body = json.loads(event.get("body", "{}"))
nome = body.get("nome")
preco = body.get("preco")
if not nome or preco is None:
return {
"statusCode": 400,
"body": json.dumps({"erro": "Nome e preco sao obrigatorios"}),
}
produto_id = str(uuid.uuid4())[:8]
produto = {
"id": produto_id,
"nome": nome,
"preco": float(preco),
"criado_em": datetime.now().isoformat(),
}
PRODUTOS[produto_id] = produto
return {
"statusCode": 201,
"body": json.dumps(produto),
}
except (json.JSONDecodeError, ValueError) as e:
return {
"statusCode": 400,
"body": json.dumps({"erro": str(e)}),
}
def buscar_produto(event, context):
"""GET /produtos/{id} - Busca um produto pelo ID."""
produto_id = event["pathParameters"]["id"]
produto = PRODUTOS.get(produto_id)
if produto is None:
return {
"statusCode": 404,
"body": json.dumps({"erro": "Produto nao encontrado"}),
}
return {
"statusCode": 200,
"body": json.dumps(produto),
}
Lambda Layers para Dependencias
Quando sua funcao precisa de bibliotecas externas, use Lambda Layers:
mkdir -p layer/python
pip install requests boto3 -t layer/python/
No template SAM:
Resources:
DependenciasLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: dependencias-python
ContentUri: layer/
CompatibleRuntimes:
- python3.12
MinhaFuncao:
Type: AWS::Serverless::Function
Properties:
Handler: app.handler
Layers:
- !Ref DependenciasLayer
Processando Eventos do S3
Lambda pode reagir a uploads no S3, ideal para processamento de arquivos:
import boto3
import json
from urllib.parse import unquote_plus
s3_client = boto3.client("s3")
def processar_upload(event, context):
"""Processa arquivos enviados ao S3."""
for registro in event["Records"]:
bucket = registro["s3"]["bucket"]["name"]
chave = unquote_plus(registro["s3"]["object"]["key"])
tamanho = registro["s3"]["object"]["size"]
print(f"Arquivo recebido: s3://{bucket}/{chave} ({tamanho} bytes)")
# Baixar e processar o arquivo
resposta = s3_client.get_object(Bucket=bucket, Key=chave)
conteudo = resposta["Body"].read().decode("utf-8")
# Exemplo: contar linhas de um CSV
linhas = conteudo.strip().split("\n")
print(f"O arquivo tem {len(linhas)} linhas")
# Salvar resultado processado
resultado = {
"arquivo_original": chave,
"total_linhas": len(linhas),
"processado": True,
}
s3_client.put_object(
Bucket=bucket,
Key=f"processados/{chave}.json",
Body=json.dumps(resultado),
ContentType="application/json",
)
return {"processados": len(event["Records"])}
Testes Locais
Testar funcoes Lambda localmente e fundamental antes do deploy:
import pytest
import json
from app import handler, criar_produto
def test_handler_basico():
evento = {"nome": "Python Brasil"}
contexto = type("Context", (), {
"function_name": "teste",
"memory_limit_in_mb": 256,
"aws_request_id": "abc-123",
})()
resultado = handler(evento, contexto)
assert resultado["statusCode"] == 200
body = json.loads(resultado["body"])
assert "Python Brasil" in body["mensagem"]
def test_criar_produto_sucesso():
evento = {
"body": json.dumps({"nome": "Teclado", "preco": 129.90})
}
resultado = criar_produto(evento, None)
assert resultado["statusCode"] == 201
body = json.loads(resultado["body"])
assert body["nome"] == "Teclado"
assert body["preco"] == 129.90
def test_criar_produto_sem_nome():
evento = {"body": json.dumps({"preco": 99.90})}
resultado = criar_produto(evento, None)
assert resultado["statusCode"] == 400
Com o SAM CLI, voce tambem pode invocar localmente:
sam local invoke ApiFunction -e events/saudacao.json
sam local start-api
Boas Praticas para Lambda em Producao
Mantenha suas funcoes pequenas e focadas em uma unica responsabilidade. Reutilize conexoes de banco e clientes AWS fora do handler para aproveitar o warm start. Defina variaveis de ambiente para configuracoes que mudam entre ambientes. Use o CloudWatch para monitorar logs, metricas e alarmes.
Configure o timeout adequado para cada funcao e ajuste a memoria conforme necessario. Mais memoria tambem significa mais CPU disponivel. Implemente tratamento de erros robusto e retorne codigos HTTP apropriados.
import os
# Variaveis de ambiente (fora do handler)
TABELA_NOME = os.environ.get("TABELA_DYNAMODB", "produtos-dev")
REGIAO = os.environ.get("AWS_REGION", "us-east-1")
# Cliente reutilizado entre invocacoes (warm start)
dynamodb = boto3.resource("dynamodb", region_name=REGIAO)
tabela = dynamodb.Table(TABELA_NOME)
Conclusao
AWS Lambda com Python e uma combinacao poderosa para construir aplicacoes escaláveis sem a complexidade de gerenciar infraestrutura. Comece com funcoes simples, teste localmente com SAM e evolua para arquiteturas serverless completas com filas, eventos do S3 e APIs REST. O ecossistema de ferramentas facilita todo o ciclo de desenvolvimento e deploy.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português