AWS Admin

O que Todo Dev Deve Saber sobre SNS: Fan-out Pattern, Filtros e Integração com SQS e Lambda Já leu

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 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.

Referências


Artigos relacionados