O que é SNS e Por Que Importa
Amazon Simple Notification Service (SNS) é um serviço de mensageria pub/sub totalmente gerenciado que desacopla componentes de sua arquitetura. Diferente de filas (como SQS), SNS trabalha com o modelo "publicador-assinante", onde uma mensagem é entregue a múltiplos receptores simultaneamente. É o padrão ideal quando você precisa que um evento dispare ações em vários sistemas independentes.
A importância do SNS está justamente nesse desacoplamento: seu serviço de pedidos não precisa conhecer o serviço de notificações, o de relatórios ou o de envio de emails. Todos se inscrevem no mesmo tópico SNS e recebem a mensagem quando precisam. Isso torna sistemas mais escaláveis, resilientes e fáceis de manter.
Fan-out Pattern: Distribuindo Mensagens em Escala
Conceito Fundamental
Fan-out é o padrão arquitetural onde uma única mensagem publicada em um tópico SNS é distribuída para múltiplos destinos (subscribers) simultaneamente. É como um broadcast: você fala uma vez e todos ouvem. Isso contrasta com arquiteturas acopladas onde o publicador precisa chamar cada consumidor manualmente.
Implementação Prática
Imagine um e-commerce onde um pedido é criado. Você publica um evento PedidoCriado no SNS e diferentes sistemas se inscrevem: sistema de pagamento, sistema de inventário, serviço de notificação ao cliente e sistema de analytics.
import boto3
import json
sns_client = boto3.client('sns', region_name='us-east-1')
def publicar_pedido_criado(pedido_id, cliente_email, valor):
"""Publica evento de pedido criado no SNS"""
mensagem = {
'pedido_id': pedido_id,
'cliente_email': cliente_email,
'valor': valor,
'timestamp': '2024-01-15T10:30:00Z'
}
response = sns_client.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:pedidos-criados',
Subject='Novo Pedido Criado',
Message=json.dumps(mensagem),
MessageStructure='json'
)
return response['MessageId']
# Uso
publicar_pedido_criado(
pedido_id='PED123',
cliente_email='cliente@example.com',
valor=299.90
)
Cada subscriber (SQS, Lambda, email, webhook) recebe essa mensagem independentemente, permitindo processamento paralelo e desacoplado.
Filtros SNS: Processamento Inteligente de Mensagens
Por Que Filtros Existem
Sem filtros, toda mensagem publicada no tópico vai para todos os subscribers. Isso gera desperdício: o sistema de pagamento recebe eventos de inventário, e vice-versa. Filtros SNS permitem que cada subscriber receba apenas mensagens relevantes baseadas em atributos.
Implementando Filtros
Filtros funcionam através de atributos de mensagem. Ao publicar, você adiciona metadados; ao subscrever, você define condições. Veja:
import boto3
import json
sns_client = boto3.client('sns', region_name='us-east-1')
sqs_client = boto3.client('sqs', region_name='us-east-1')
# Publicando com atributos
def publicar_com_atributos(pedido_valor, tipo_pedido):
"""Publica com atributos para filtro"""
sns_client.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:pedidos',
Message='Novo pedido processado',
MessageAttributes={
'tipo': {
'StringValue': tipo_pedido, # 'premium' ou 'normal'
'DataType': 'String'
},
'valor': {
'StringValue': str(pedido_valor),
'DataType': 'Number'
}
}
)
# Subscribe com filtro policy
def subscrever_com_filtro(fila_url, topico_arn):
"""Cria subscription com filtro para pedidos premium acima de R$500"""
filter_policy = {
'tipo': ['premium'],
'valor': [{'numeric': ['>=', 500]}]
}
response = sns_client.subscribe(
TopicArn=topico_arn,
Protocol='sqs',
Endpoint=fila_url,
Attributes={
'FilterPolicy': json.dumps(filter_policy)
}
)
return response['SubscriptionArn']
publicar_com_atributos(750.00, 'premium')
publicar_com_atributos(150.00, 'normal')
# A fila recebe apenas o primeiro
Apenas mensagens que correspondem aos critérios são entregues, economizando processamento e custos.
Integração SNS + SQS + Lambda
Arquitetura Completa
A combinação SNS → SQS → Lambda é poderosa: SNS garante que múltiplos sistemas saibam do evento, SQS oferece fila durável (retry automático, dead-letter queue), e Lambda processa em paralelo sem gerenciar servidores. SNS publica, SQS armazena temporariamente, Lambda consome.
Código Funcional Completo
import boto3
import json
from datetime import datetime
sns = boto3.client('sns')
sqs = boto3.client('sqs')
lambda_client = boto3.client('lambda')
# 1. Publisher: Publicar evento no SNS
def publicar_evento_pedido(pedido_id, cliente_id):
"""Publica evento no tópico SNS"""
mensagem = {
'pedido_id': pedido_id,
'cliente_id': cliente_id,
'timestamp': datetime.now().isoformat()
}
sns.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:eventos-pedidos',
Message=json.dumps(mensagem),
MessageAttributes={
'evento_tipo': {
'StringValue': 'pedido.criado',
'DataType': 'String'
}
}
)
# 2. Lambda Handler: Consumir de SQS
def lambda_handler(event, context):
"""Lambda acionada por mensagens SQS (originalmente do SNS)"""
for record in event['Records']:
# SQS envolve a mensagem original em um JSON
body = json.loads(record['body'])
message = json.loads(body['Message'])
pedido_id = message['pedido_id']
cliente_id = message['cliente_id']
# Processar pedido
print(f"Processando pedido {pedido_id} do cliente {cliente_id}")
# Lógica de negócio aqui
enviar_confirmacao_email(cliente_id)
atualizar_inventario(pedido_id)
return {
'statusCode': 200,
'body': json.dumps('Pedidos processados')
}
def enviar_confirmacao_email(cliente_id):
"""Simula envio de email"""
print(f"Email enviado para cliente {cliente_id}")
def atualizar_inventario(pedido_id):
"""Simula atualização de inventário"""
print(f"Inventário atualizado para pedido {pedido_id}")
# 3. Setup (executar uma única vez)
def configurar_arquitetura():
"""Configura SNS → SQS → Lambda"""
# Criar fila SQS
fila = sqs.create_queue(
QueueName='pedidos-processamento',
Attributes={
'VisibilityTimeout': '300',
'MessageRetentionPeriod': '86400'
}
)
fila_url = fila['QueueUrl']
# Inscrever fila no tópico SNS
sns.subscribe(
TopicArn='arn:aws:sns:us-east-1:123456789012:eventos-pedidos',
Protocol='sqs',
Endpoint=fila_url
)
print(f"Arquitetura configurada. Fila: {fila_url}")
O fluxo é: publicar_evento_pedido() → SNS publica → SQS recebe → Lambda processa. Se Lambda falhar, a mensagem volta à fila automaticamente (retry).
Conclusão
Três pilares para dominar SNS: primeiro, entenda que SNS é publicador-assinante para eventos distribuídos, não filas. Segundo, use filtros SNS para rotear mensagens inteligentemente e economizar processamento. Terceiro, combine SNS + SQS + Lambda para arquiteturas robustas, desacopladas e escaláveis que processam eventos em paralelo sem deixar nenhum cair.