AWS SNS - Notificações Pub/Sub
O que é este Node?
O AWS SNS é o node responsável por enviar notificações em massa via Amazon SNS (Simple Notification Service), permitindo publicar mensagens para múltiplos assinantes, enviar SMS e gerenciar tópicos.
Por que este Node existe?
Sistemas precisam notificar múltiplos componentes simultaneamente. O AWS SNS existe para:
- Broadcasting: Enviar uma mensagem para múltiplos destinos ao mesmo tempo
- Fan-out pattern: Disparar múltiplas ações a partir de um evento
- SMS em massa: Enviar mensagens SMS para telefones
- Push notifications: Notificar aplicativos mobile
- Integração multi-canal: Email, SMS, HTTP, Lambda, SQS simultaneamente
- Desacoplamento: Publicadores não precisam conhecer assinantes
Como funciona internamente?
Quando o AWS SNS é executado, o sistema:
- Autentica usando accessKeyId e secretAccessKey
- Cria cliente SNS configurado para região especificada
- Executa operação conforme especificado (publish, subscribe, createTopic, sendSMS)
- Distribui mensagem para todos os assinantes do tópico
- Retorna resultado com messageId ou subscriptionArn
- Se erro: Lança exceção com detalhes
Código interno (aws-executors.service.ts:161-222):
async executeAWSSNS(data: any, variables: Record<string, any>): Promise<any> {
try {
this.logger.log('🔔 [AWS SNS] Executing operation');
const sns = new AWS.SNS({
accessKeyId: data.accessKeyId,
secretAccessKey: data.secretAccessKey,
region: data.region,
});
switch (data.operation) {
case 'publish':
const publishResult = await sns.publish({
TopicArn: data.topicArn,
Message: data.message,
Subject: data.subject,
MessageAttributes: data.messageAttributes,
}).promise();
return {
success: true,
messageId: publishResult.MessageId,
};
case 'subscribe':
const subscribeResult = await sns.subscribe({
TopicArn: data.topicArn,
Protocol: data.protocol,
Endpoint: data.endpoint,
}).promise();
return {
success: true,
subscriptionArn: subscribeResult.SubscriptionArn,
};
case 'createTopic':
const createTopicResult = await sns.createTopic({
Name: data.topicName,
Attributes: data.attributes,
}).promise();
return {
success: true,
topicArn: createTopicResult.TopicArn,
};
case 'sendSMS':
const smsResult = await sns.publish({
PhoneNumber: data.phoneNumber,
Message: data.message,
}).promise();
return {
success: true,
messageId: smsResult.MessageId,
};
default:
throw new Error(`Unknown SNS operation: ${data.operation}`);
}
} catch (error) {
this.logger.error('AWS SNS execution error:', error);
throw error;
}
}
Quando você DEVE usar este Node?
Use AWS SNS quando precisar de notificações para múltiplos destinos:
Casos de uso:
- Alertas críticos: Notificar equipe via SMS, email e Slack simultaneamente
- Eventos de negócio: Disparar múltiplas ações quando pedido é criado
- SMS transacional: Enviar códigos de verificação, confirmações
- Push notifications: Notificar apps mobile sobre eventos
- Webhook fan-out: Chamar múltiplas APIs quando algo acontece
- Monitoramento: Alertas de CloudWatch para múltiplos canais
Quando NÃO usar AWS SNS:
- Fila de trabalho: Use SQS (SNS não garante ordem nem reprocessamento)
- Mensagem única: Use SES para email ou direct SMS
- Armazenamento: Use DynamoDB ou S3
- Processamento em batch: Use SQS + Lambda
Parâmetros Detalhados
accessKeyId (string, obrigatório)
O que é: Chave de acesso AWS IAM para autenticação.
Segurança: NUNCA exponha em código! Use variáveis de ambiente.
secretAccessKey (string, obrigatório)
O que é: Chave secreta AWS IAM correspondente ao accessKeyId.
Segurança: NUNCA exponha em código! Use variáveis de ambiente.
region (string, obrigatório)
O que é: Região AWS onde o tópico está localizado.
Exemplos: us-east-1, us-west-2, sa-east-1 (São Paulo)
operation (string, obrigatório)
O que é: Operação a ser executada.
Valores possíveis:
- publish: Publicar mensagem em tópico
- subscribe: Inscrever endpoint em tópico
- createTopic: Criar novo tópico
- sendSMS: Enviar SMS direto (sem tópico)
topicArn (string, obrigatório para publish/subscribe)
O que é: ARN (Amazon Resource Name) do tópico SNS.
Formato: arn:aws:sns:{region}:{account-id}:{topic-name}
Flow completo para testar publish:
{
"name": "Teste AWS SNS - Publish",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Dados do Alerta",
"parameters": {
"assignments": [
{
"variable": "alerta",
"value": {
"tipo": "Erro Crítico",
"sistema": "API de Pagamentos",
"mensagem": "Taxa de erro acima de 5%",
"timestamp": "{{$now}}"
}
}
]
}
}
},
{
"id": "sns_1",
"type": "aws_sns",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Notificar Equipe",
"parameters": {
"accessKeyId": "{{AWS_ACCESS_KEY}}",
"secretAccessKey": "{{AWS_SECRET_KEY}}",
"region": "sa-east-1",
"operation": "publish",
"topicArn": "arn:aws:sns:sa-east-1:123456789:alertas-criticos",
"subject": "🚨 ALERTA: {{alerta.tipo}}",
"message": "Sistema: {{alerta.sistema}}\n{{alerta.mensagem}}\n\nTimestamp: {{alerta.timestamp}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "✅ Alerta enviado para equipe!\nMessage ID: {{messageId}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "variable_1" },
{ "source": "variable_1", "target": "sns_1" },
{ "source": "sns_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Mensagem é publicada no tópico e todos os assinantes (email, SMS, Lambda, etc.) recebem.
message (string, obrigatório)
O que é: Conteúdo da mensagem a ser publicada/enviada.
Formato: String de texto (pode incluir JSON se assinantes processarem)
subject (string, opcional para publish)
O que é: Assunto da mensagem (usado em notificações por email).
Limite: 100 caracteres
phoneNumber (string, obrigatório para sendSMS)
O que é: Número de telefone no formato internacional.
Formato: +55119xxxxxxxx (+ código país + DDD + número)
Flow completo para testar sendSMS:
{
"name": "Teste AWS SNS - Send SMS",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Pedir Telefone",
"parameters": {
"message": "Digite seu telefone com DDD (ex: 11987654321):",
"variable": "telefone"
}
}
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Formatar Número",
"parameters": {
"assignments": [
{
"variable": "telefoneInternacional",
"value": "+55{{telefone}}"
},
{
"variable": "codigoVerificacao",
"value": "{{$random(100000,999999)}}"
}
]
}
}
},
{
"id": "sns_1",
"type": "aws_sns",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Enviar SMS",
"parameters": {
"accessKeyId": "{{AWS_ACCESS_KEY}}",
"secretAccessKey": "{{AWS_SECRET_KEY}}",
"region": "sa-east-1",
"operation": "sendSMS",
"phoneNumber": "{{telefoneInternacional}}",
"message": "Seu código de verificação é: {{codigoVerificacao}}\n\nNão compartilhe este código."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "📱 SMS enviado para {{telefoneInternacional}}!\n\nCódigo: {{codigoVerificacao}}\nMessage ID: {{messageId}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1100, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "variable_1" },
{ "source": "variable_1", "target": "sns_1" },
{ "source": "sns_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: SMS é enviado para número especificado.
protocol (string, obrigatório para subscribe)
O que é: Protocolo do endpoint que receberá notificações.
Valores possíveis:
- email: Email comum
- email-json: Email com JSON
- sms: SMS
- http: Webhook HTTP
- https: Webhook HTTPS
- lambda: Função Lambda
- sqs: Fila SQS
- application: Mobile push
endpoint (string, obrigatório para subscribe)
O que é: Destino que receberá as notificações.
Exemplos:
- Email: jose@empresa.com.br
- HTTP: https://api.empresa.com.br/webhook/sns
- Lambda: arn:aws:lambda:sa-east-1:123456789:function:processar-notificacao
- SQS: arn:aws:sqs:sa-east-1:123456789:minha-fila
Flow completo para testar subscribe:
{
"name": "Teste AWS SNS - Subscribe",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Pedir Email",
"parameters": {
"message": "Digite seu email para receber alertas:",
"variable": "email"
}
}
},
{
"id": "sns_1",
"type": "aws_sns",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Inscrever Email",
"parameters": {
"accessKeyId": "{{AWS_ACCESS_KEY}}",
"secretAccessKey": "{{AWS_SECRET_KEY}}",
"region": "sa-east-1",
"operation": "subscribe",
"topicArn": "arn:aws:sns:sa-east-1:123456789:alertas-criticos",
"protocol": "email",
"endpoint": "{{email}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "✅ Email {{email}} inscrito no tópico de alertas!\n\nVerifique sua caixa de entrada para confirmar a inscrição.\n\nSubscription ARN: {{subscriptionArn}}"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 900, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "sns_1" },
{ "source": "sns_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Teste: Email recebe confirmação de inscrição no tópico.
topicName (string, obrigatório para createTopic)
O que é: Nome do novo tópico a ser criado.
Regras: Letras, números, hífens e underscores. Máximo 256 caracteres.
Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| accessKeyId | string | Sim | Chave de acesso AWS IAM |
| secretAccessKey | string | Sim | Chave secreta AWS IAM |
| region | string | Sim | Região AWS (ex: sa-east-1) |
| operation | string | Sim | publish, subscribe, createTopic, sendSMS |
| topicArn | string | Condicional | ARN do tópico (publish/subscribe) |
| message | string | Sim | Conteúdo da mensagem |
| subject | string | Não | Assunto (usado em email) |
| phoneNumber | string | Condicional | Telefone internacional (sendSMS) |
| protocol | string | Condicional | Protocolo do assinante (subscribe) |
| endpoint | string | Condicional | Destino da notificação (subscribe) |
| topicName | string | Condicional | Nome do tópico (createTopic) |
| messageAttributes | object | Não | Metadados customizados |
| attributes | object | Não | Configurações do tópico/assinatura |
Exemplo 1: Sistema de Alertas Multi-Canal
Objetivo: Enviar alertas críticos para SMS, email e Lambda simultaneamente
JSON para Importar
{
"name": "AWS SNS - Alertas Multi-Canal",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "input_1",
"type": "input",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Tipo de Alerta",
"parameters": {
"message": "Qual tipo de alerta?\n1 - CPU Alta\n2 - Disco Cheio\n3 - API Down",
"variable": "tipoAlerta"
}
}
},
{
"id": "switch_1",
"type": "switch",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Identificar Alerta",
"parameters": {
"variable": "tipoAlerta",
"cases": [
{
"value": "1",
"nextNode": "var_cpu"
},
{
"value": "2",
"nextNode": "var_disco"
},
{
"value": "3",
"nextNode": "var_api"
}
]
}
}
},
{
"id": "var_cpu",
"type": "variable",
"position": { "x": 700, "y": 50 },
"data": {
"label": "Alerta CPU",
"parameters": {
"assignments": [
{
"variable": "alertaMensagem",
"value": "🚨 CPU acima de 90% por 5 minutos!\n\nServidor: prod-api-1\nCPU Atual: 94%\nAção Recomendada: Investigar processos"
}
]
}
}
},
{
"id": "var_disco",
"type": "variable",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Alerta Disco",
"parameters": {
"assignments": [
{
"variable": "alertaMensagem",
"value": "💾 Disco com 95% de uso!\n\nServidor: prod-db-1\nEspaço Livre: 2GB\nAção Recomendada: Limpar logs antigos"
}
]
}
}
},
{
"id": "var_api",
"type": "variable",
"position": { "x": 700, "y": 150 },
"data": {
"label": "Alerta API",
"parameters": {
"assignments": [
{
"variable": "alertaMensagem",
"value": "⚠️ API não responde!\n\nEndpoint: /api/pagamentos\nStatus: Timeout após 30s\nAção Recomendada: Verificar logs e reiniciar"
}
]
}
}
},
{
"id": "sns_1",
"type": "aws_sns",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Notificar Todos",
"parameters": {
"accessKeyId": "{{AWS_ACCESS_KEY}}",
"secretAccessKey": "{{AWS_SECRET_KEY}}",
"region": "sa-east-1",
"operation": "publish",
"topicArn": "arn:aws:sns:sa-east-1:123456789:alertas-infraestrutura",
"subject": "🚨 ALERTA CRÍTICO - Infraestrutura",
"message": "{{alertaMensagem}}\n\nTimestamp: {{$now}}"
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Confirmar",
"parameters": {
"message": "✅ Alerta enviado para TODOS os canais!\n\n📧 Email\n📱 SMS\n⚡ Lambda\n\nEquipe notificada!"
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1300, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "input_1" },
{ "source": "input_1", "target": "switch_1" },
{ "source": "var_cpu", "target": "sns_1" },
{ "source": "var_disco", "target": "sns_1" },
{ "source": "var_api", "target": "sns_1" },
{ "source": "sns_1", "target": "message_1" },
{ "source": "message_1", "target": "end_1" }
]
}
Saída esperada:
Sistema: Qual tipo de alerta?
1 - CPU Alta
2 - Disco Cheio
3 - API Down
Usuário: 1
Sistema: ✅ Alerta enviado para TODOS os canais!
📧 Email
📱 SMS
⚡ Lambda
Equipe notificada!
Exemplo 2: Sistema de Verificação 2FA via SMS
Objetivo: Enviar código de verificação por SMS usando SNS
JSON para Importar
{
"name": "AWS SNS - 2FA SMS",
"nodes": [
{
"id": "start_1",
"type": "start",
"position": { "x": 100, "y": 100 },
"data": { "label": "Início" }
},
{
"id": "phone_1",
"type": "phone",
"position": { "x": 300, "y": 100 },
"data": {
"label": "Solicitar Telefone",
"parameters": {
"message": "Digite seu celular com DDD:",
"variable": "telefone"
}
}
},
{
"id": "variable_1",
"type": "variable",
"position": { "x": 500, "y": 100 },
"data": {
"label": "Gerar Código",
"parameters": {
"assignments": [
{
"variable": "codigo2FA",
"value": "{{$random(100000,999999)}}"
},
{
"variable": "telefoneInternacional",
"value": "+55{{telefone}}"
}
]
}
}
},
{
"id": "sns_sms",
"type": "aws_sns",
"position": { "x": 700, "y": 100 },
"data": {
"label": "Enviar Código SMS",
"parameters": {
"accessKeyId": "{{AWS_ACCESS_KEY}}",
"secretAccessKey": "{{AWS_SECRET_KEY}}",
"region": "sa-east-1",
"operation": "sendSMS",
"phoneNumber": "{{telefoneInternacional}}",
"message": "Seu código de verificação Lumina:\n\n{{codigo2FA}}\n\nVálido por 5 minutos.\nNão compartilhe este código."
}
}
},
{
"id": "message_1",
"type": "message",
"position": { "x": 900, "y": 100 },
"data": {
"label": "Informar",
"parameters": {
"message": "📱 Código enviado para {{telefone}}!\n\nDigite o código de 6 dígitos:"
}
}
},
{
"id": "number_1",
"type": "number",
"position": { "x": 1100, "y": 100 },
"data": {
"label": "Receber Código",
"parameters": {
"message": "Digite o código:",
"variable": "codigoDigitado",
"min": 100000,
"max": 999999
}
}
},
{
"id": "condition_1",
"type": "condition",
"position": { "x": 1300, "y": 100 },
"data": {
"label": "Validar",
"parameters": {
"conditions": [
{
"variable": "codigoDigitado",
"operator": "==",
"value": "{{codigo2FA}}",
"nextNode": "message_success"
}
],
"defaultNextNode": "message_error"
}
}
},
{
"id": "message_success",
"type": "message",
"position": { "x": 1500, "y": 50 },
"data": {
"label": "Sucesso",
"parameters": {
"message": "✅ Código correto!\n\nVerificação 2FA concluída com sucesso."
}
}
},
{
"id": "message_error",
"type": "message",
"position": { "x": 1500, "y": 150 },
"data": {
"label": "Erro",
"parameters": {
"message": "❌ Código incorreto!\n\nTente novamente."
}
}
},
{
"id": "end_1",
"type": "end",
"position": { "x": 1700, "y": 100 },
"data": { "label": "Fim" }
}
],
"edges": [
{ "source": "start_1", "target": "phone_1" },
{ "source": "phone_1", "target": "variable_1" },
{ "source": "variable_1", "target": "sns_sms" },
{ "source": "sns_sms", "target": "message_1" },
{ "source": "message_1", "target": "number_1" },
{ "source": "number_1", "target": "condition_1" },
{ "source": "message_success", "target": "end_1" },
{ "source": "message_error", "target": "end_1" }
]
}
Saída esperada:
Sistema: Digite seu celular com DDD:
Usuário: 11987654321
Sistema: 📱 Código enviado para 11987654321!
Digite o código de 6 dígitos:
Usuário: 847392
Sistema: ✅ Código correto!
Verificação 2FA concluída com sucesso.
Resposta do Node
Publish:
{
"success": true,
"messageId": "abc123-def456-ghi789"
}
Subscribe:
{
"success": true,
"subscriptionArn": "arn:aws:sns:sa-east-1:123456789:alertas:abc123-def456"
}
CreateTopic:
{
"success": true,
"topicArn": "arn:aws:sns:sa-east-1:123456789:meu-topico"
}
SendSMS:
{
"success": true,
"messageId": "sms-abc123-def456"
}
Boas Práticas
✅ SIM:
- Use tópicos para notificar múltiplos destinos
- Configure filtros de mensagem para assinantes específicos
- Use messageAttributes para metadados estruturados
- Implemente idempotência (MessageId para deduplicação)
- Configure Dead Letter Queue (DLQ) para falhas
- Use FIFO topics quando ordem for crítica
- Monitore métricas (NumberOfMessagesPublished, NumberOfNotificationsFailed)
❌ NÃO:
- Não use SNS para filas de trabalho (use SQS)
- Não envie mensagens > 256KB
- Não exponha credenciais AWS em código
- Não confie em ordem de entrega (use FIFO se necessário)
- Não ignore erros de publicação
Dicas
💡 SMS Sandbox: Conta nova AWS precisa verificar números antes de enviar SMS 💡 Custos: Calcule custos por mensagem (varia por protocolo e região) 💡 Fan-out: Combine SNS → SQS para processamento paralelo confiável 💡 Filtros: Use subscription filter policies para routing inteligente 💡 Retry: SNS retenta automaticamente entregas com falha 💡 Mobile Push: Configure plataformas (APNS, FCM) antes de usar 💡 Cross-region: SNS não replica entre regiões automaticamente
Próximo Node
→ AWS SQS - Fila de mensagens → AWS DYNAMODB - Banco de dados NoSQL → AWS LAMBDA - Executar funções serverless