Pular para o conteúdo principal

Lab: Solução de Problemas Lambda

Objetivo​

Diagnosticar e corrigir funções Lambda com falhas utilizando uma abordagem metódica.

Exercício 1: Timeout​

Código com Problema​

# buggy_timeout.py
import time
import json

def lambda_handler(event, context):
"""
Esta função tem um problema de timeout
"""
print("Starting processing...")

# Simulação de processamento longo
data = event.get('data', [])

for item in data:
# Processamento muito lento
time.sleep(2) # 2 segundos por item!
print(f"Processed: {item}")

return {
'statusCode': 200,
'body': json.dumps({'processed': len(data)})
}

Configuração​

  • Timeout: 3 segundos
  • Payload: {"data": ["a", "b", "c", "d", "e"]}

Perguntas​

  1. Por que essa função falha?
  2. Calcule o tempo total necessário
  3. Proponha 2 soluções diferentes
💡 Solução

1. Por quê:

  • 5 itens × 2 segundos = 10 segundos no mínimo
  • Timeout = 3 segundos
  • A função é interrompida antes de terminar

2. Tempo necessário:

  • Processamento: 5 × 2s = 10s
  • Overhead Lambda: ~100ms
  • Total: ~10,1 segundos

3. Soluções:

Solução A: Aumentar o timeout

aws lambda update-function-configuration \
--function-name buggy-timeout \
--timeout 30

Solução B: Otimizar o código

import json
from concurrent.futures import ThreadPoolExecutor

def process_item(item):
# Processamento (simulado com sleep reduzido)
return f"Processed: {item}"

def lambda_handler(event, context):
data = event.get('data', [])

# Processamento paralelo
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(process_item, data))

return {
'statusCode': 200,
'body': json.dumps({'results': results})
}

Exercício 2: Erro de Permissões​

Código​

# buggy_permissions.py
import json
import boto3

def lambda_handler(event, context):
"""
Esta função tenta ler do S3
"""
s3 = boto3.client('s3')

bucket = event['bucket']
key = event['key']

try:
response = s3.get_object(Bucket=bucket, Key=key)
content = response['Body'].read().decode('utf-8')

return {
'statusCode': 200,
'body': json.dumps({'content': content[:100]})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}

Erro Recebido​

{
"statusCode": 500,
"body": "{\"error\": \"An error occurred (AccessDenied) when calling the GetObject operation: Access Denied\"}"
}

Perguntas​

  1. Qual é a causa do erro?
  2. Qual política IAM deve ser adicionada?
  3. Escreva o comando AWS CLI para corrigir
💡 Solução

1. Causa: O role de execução do Lambda não possui permissão s3:GetObject

2. Política IAM a ser adicionada:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}

3. Comandos CLI:

# Criar a política
cat > s3-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}
EOF

# Anexar ao role
aws iam put-role-policy \
--role-name lambda-role \
--policy-name S3ReadAccess \
--policy-document file://s3-policy.json

Exercício 3: Out of Memory​

Código com Problema​

# buggy_memory.py
import json

def lambda_handler(event, context):
"""
Esta função tem um problema de memória
"""
size = event.get('size', 1000000)

# Cria uma lista enorme em memória
data = []
for i in range(size):
data.append({
'id': i,
'name': f'Item {i}',
'description': 'A' * 1000 # 1KB por item
})

return {
'statusCode': 200,
'body': json.dumps({'count': len(data)})
}

Configuração​

  • Memória: 128 MB
  • Payload: {"size": 100000} (100K itens × ~1KB = ~100MB)

Perguntas​

  1. Por que a função falha?
  2. Qual memória você recomenda?
  3. Como otimizar sem aumentar a memória?
💡 Solução

1. Por quê:

  • 100.000 itens × ~1KB = ~100MB de dados
  • Overhead Python/Lambda: ~30-50MB
  • Total: ~130-150MB > 128MB configurado

2. Memória recomendada:

  • Mínimo: 256 MB (com margem)
  • Recomendado: 512 MB (para segurança)
aws lambda update-function-configuration \
--function-name buggy-memory \
--memory-size 512

3. Otimização sem mais memória:

import json

def lambda_handler(event, context):
size = event.get('size', 1000000)

# Processamento em batch com generator
def process_batch(start, end):
for i in range(start, end):
yield {'id': i, 'processed': True}

# Processar em chunks de 10000
batch_size = 10000
total_processed = 0

for batch_start in range(0, size, batch_size):
batch_end = min(batch_start + batch_size, size)

# Processar o batch (não mantém tudo em memória)
for item in process_batch(batch_start, batch_end):
total_processed += 1

# Libera a memória entre os batches

return {
'statusCode': 200,
'body': json.dumps({'processed': total_processed})
}

Exercício 4: Handler Not Found​

Configuração​

  • Arquivo: my_function.py
  • Handler configurado: lambda_function.handler

Erro​

{
"errorMessage": "Unable to import module 'lambda_function': No module named 'lambda_function'",
"errorType": "Runtime.ImportModuleError"
}

Perguntas​

  1. Qual é o erro de configuração?
  2. Qual valor de handler está correto?
  3. Liste 3 erros comuns de handler
💡 Solução

1. Erro: O handler está configurado como lambda_function.handler mas o arquivo se chama my_function.py

2. Handler correto:

my_function.handler

Formato: <nome_arquivo_sem_extensão>.<nome_função>

3. Erros comuns:

  1. Nome de arquivo incorreto (lambda_function vs my_function)
  2. Nome de função incorreto (handler vs lambda_handler)
  3. Arquivo em subdiretório (src/handler.main ao invés de handler.main)
  4. Inclusão da extensão por engano (handler.py.main)
  5. Case incorreto (Handler vs handler)

Exercício 5: Diagnóstico Completo​

Cenário​

Uma função Lambda retorna erros intermitentes. Veja as informações disponíveis:

Logs CloudWatch:

START RequestId: abc-123
[INFO] Connecting to database...
END RequestId: abc-123
REPORT RequestId: abc-123 Duration: 29987.45 ms Billed Duration: 30000 ms Memory Size: 256 MB Max Memory Used: 89 MB Init Duration: 1234.56 ms

START RequestId: def-456
[INFO] Connecting to database...
[ERROR] Connection timed out
END RequestId: def-456
REPORT RequestId: def-456 Duration: 30000.00 ms Billed Duration: 30000 ms Memory Size: 256 MB Max Memory Used: 67 MB

Configuração:

  • Timeout: 30 segundos
  • Memória: 256 MB
  • VPC: Sim (sub-rede privada)

Perguntas​

Preencha a tabela de diagnóstico:

ElementoObservaçãoProblema PotencialAção
Duration???
Memory???
Init Duration???
Error message???
VPC???
💡 Solução
ElementoObservaçãoProblema PotencialAção
Duration~30s (timeout)Conexão DB lenta/bloqueadaTimeout DB + retry
Memory67-89 MB / 256 MBOK, sem problema de memória-
Init Duration1234msCold start elevadoOtimizar ou Provisioned
Error messageConnection timed outDB inacessívelVerificar SG, NAT
VPCSub-rede privadaSem NAT para saída Internet?Adicionar NAT Gateway

Diagnóstico: A função está em uma VPC privada sem NAT Gateway. Ela não consegue acessar o banco de dados externo.

Soluções:

  1. Adicionar um NAT Gateway à sub-rede privada
  2. Ou colocar o banco de dados na mesma VPC
  3. Ou usar VPC Endpoints se o banco for um serviço AWS
  4. Adicionar timeouts de conexão no código

Exercício 6: Escrever Logs de Qualidade​

Código Antes (logs ruins)​

def lambda_handler(event, context):
print("Starting")
# ... código ...
print("Done")
return result

Exercício​

Reescreva o código com logs de qualidade que facilitem o troubleshooting:

💡 Solução
import json
import logging

# Configuração do logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
# Log estruturado da entrada
logger.info(json.dumps({
'action': 'start',
'request_id': context.aws_request_id,
'event_keys': list(event.keys()),
'remaining_time_ms': context.get_remaining_time_in_millis()
}))

try:
# Sua lógica
user_id = event.get('user_id')
logger.info(f"Processing user: {user_id}")

result = process_user(user_id)

# Log de sucesso
logger.info(json.dumps({
'action': 'complete',
'request_id': context.aws_request_id,
'user_id': user_id,
'status': 'success'
}))

return {'statusCode': 200, 'body': json.dumps(result)}

except Exception as e:
# Log de erro detalhado
logger.error(json.dumps({
'action': 'error',
'request_id': context.aws_request_id,
'error_type': type(e).__name__,
'error_message': str(e),
'user_id': event.get('user_id')
}), exc_info=True)

return {'statusCode': 500, 'body': json.dumps({'error': str(e)})}

Entregável​

Documento a Produzir​

  1. Soluções para os 6 exercícios
  2. Tabela de diagnóstico preenchida
  3. Código corrigido para cada bug
  4. Recomendações de boas práticas

Critérios de Avaliação​

CritérioPontos
Diagnóstico correto/25
Soluções apropriadas/25
Código corrigido funcional/25
Qualidade dos logs/15
Documentação/10
Total/100

Semana seguinte: MÓDULO 13 - Observabilidade