Alertas de e-mail personalizados e escalonamentos: roteamento avançado de incidentes
Crie workflows de escalonamento que acionam a pessoa certa no momento certo. Guia de roteamento de alertas, integração on-call e políticas de escalonamento.
O problema do escalonamento#
São 3 da manhã. Seu site cai. Você precisa que alguém responda imediatamente.
Sem escalonamento:
- O alerta dispara no canal Slack do on-call
- Ninguém vê (todo mundo dormindo, notificações do Slack desligadas)
- 45 minutos depois, reclamações de clientes acordam alguém
- MTTR: 45 minutos
Com escalonamento inteligente:
- O alerta dispara no Slack (prioridade baixa)
- Se ninguém confirmar em 2 minutos → SMS para o primário on-call
- Se não houver resposta em 5 minutos → ligação para o backup on-call
- MTTR: 5 minutos
Este guia mostra como construir workflows de escalonamento inteligentes.
Entendendo a severidade do incidente#
Primeiro, classifique os incidentes por severidade:
Tier 1: Crítico (notificação imediata)#
- Site de produção fora do ar (impacto em receita)
- Falha no gateway de pagamento
- API retornando erros 5xx
- Replicação do banco de dados caída
Ações:
- Slack #critical-incidents (sempre monitorado)
- SMS para o primário on-call
- Ligação telefônica se não houver resposta ao SMS
- Criação automática de ticket no Jira
- Atualização da status page
Tier 2: Aviso (notificação em horário comercial)#
- Degradação de tempo de resposta
- Erros em serviços não críticos
- Problemas de deliverability de e-mail
- Lentidão em queries do banco de dados
Ações:
- Slack #alerts (verificado em horário comercial)
- Criação de ticket no Jira
- Resumo por e-mail no fim do dia
Tier 3: Info (apenas log)#
- Vencimento de domínio em 30 dias
- Vencimento de SSL em 90 dias
- Relatório semanal de tendências
- Limiar de métrica não crítica
Ações:
- Resumo semanal por e-mail
- Notificação no dashboard (sem push)
Construindo sua política de escalonamento#
Passo 1: defina as rotações on-call#
Crie uma rotação que mostre quem está on-call e quando:
Seg-Sex 9h - 17h: Alice (primário), Bob (backup)
Seg-Sex 17h - 9h: Charlie (primário), Diana (backup)
Sáb-Dom 24h: Eve (primário), Frank (backup)
Feriados: George (on-call o dia todo)
Passo 2: defina os tempos de escalonamento#
T+0: O alerta dispara no Slack
T+2min: Sem confirmação → SMS para o primário
T+5min: Sem resposta → ligação para o primário
T+10min: Sem resposta → SMS para o backup
T+15min: Ainda sem resposta → notifica o time inteiro
Passo 3: implemente a lógica de escalonamento#
No Nova Uptime (se suportado):
- Configurações do domínio → Alertas
- Defina severidade: Crítico
- Configure o escalonamento:
- Passo 1: Slack #critical-incidents
- Passo 2 (2 min): SMS para o on-call
- Passo 3 (5 min): ligação telefônica
- Passo 4 (10 min): time inteiro
Via Webhook + sistema customizado:
async function handleCriticalIncident({ domain, detectedAt }) {
const oncall = await getOnCallEngineer(new Date());
// Step 1: Immediate Slack alert
const slackMessage = await postToSlack({
channel: '#critical-incidents',
text: `🚨 CRITICAL: ${domain} is down`,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `@${oncall.slackHandle}: ${domain} is down. Acknowledge with reaction.`
}
}
]
});
// Step 2: Wait 2 minutes for acknowledgment
const acknowledged = await waitForAcknowledgment(slackMessage, 2 * 60 * 1000);
if (!acknowledged) {
// Step 2: Send SMS
await sendSMS({
to: oncall.phone,
message: `CRITICAL: ${domain} down. Reply OK to acknowledge.`
});
}
// Step 3: Wait 5 minutes total
const smsAcknowledged = await waitForSMS(oncall.phone, 5 * 60 * 1000);
if (!smsAcknowledged) {
// Step 3: Phone call
await makePhoneCall({
to: oncall.phone,
message: `Critical incident. Website ${domain} is down. Press 1 to acknowledge.`
});
}
// ... Continue escalation chain
}
Avançado: roteamento inteligente de alertas#
Padrão 1: roteamento por horário do dia#
Pessoas diferentes on-call em horários diferentes.
async function getOnCallEngineer(timestamp) {
const hour = new Date(timestamp).getHours();
const dayOfWeek = new Date(timestamp).getDay();
// Business hours (9 AM - 5 PM weekdays)
if (dayOfWeek >= 1 && dayOfWeek <= 5 && hour >= 9 && hour < 17) {
return {
name: 'Alice',
slackHandle: 'alice',
phone: '+1-555-0100',
email: 'alice@company.com'
};
}
// After hours (weekdays)
if (dayOfWeek >= 1 && dayOfWeek <= 5 && (hour < 9 || hour >= 17)) {
return {
name: 'Charlie',
slackHandle: 'charlie',
phone: '+1-555-0102',
email: 'charlie@company.com'
};
}
// Weekend
if (dayOfWeek === 0 || dayOfWeek === 6) {
return {
name: 'Eve',
slackHandle: 'eve',
phone: '+1-555-0104',
email: 'eve@company.com'
};
}
}
Padrão 2: roteamento por domínio#
Times diferentes são donos de domínios diferentes.
async function getTeamForDomain(domain) {
// Engineering team owns api.*, backend.*
if (domain.startsWith('api.') || domain.startsWith('backend.')) {
return 'engineering';
}
// Infrastructure team owns server, monitoring, infra
if (domain.includes('server') || domain.includes('monitor')) {
return 'infrastructure';
}
// Support team owns customer-facing domains
if (domain.startsWith('support.') || domain.startsWith('customer.')) {
return 'support';
}
// Default: DevOps
return 'devops';
}
async function handleIncident({ domain, severity }) {
const team = await getTeamForDomain(domain);
const oncall = await getOnCallEngineer(team, new Date());
if (severity === 'critical') {
await escalate(oncall);
}
}
Padrão 3: roteamento por tipo de incidente#
Especialistas diferentes para falhas diferentes.
async function getExpertForIncident(domain, incidentType) {
if (incidentType === 'database_down') {
// Page database expert
return await getOnCallExpert('database');
} else if (incidentType === 'api_errors') {
// Page API lead
return await getOnCallExpert('backend');
} else if (incidentType === 'email_delivery_failing') {
// Page email ops
return await getOnCallExpert('email');
} else if (incidentType === 'ssl_expired') {
// Page security
return await getOnCallExpert('security');
}
// Default: on-call engineer
return await getOnCallEngineer(new Date());
}
Padrão 4: escalonamento condicional#
Caminhos de escalonamento diferentes com base nas propriedades do incidente.
async function escalateIncident({ domain, severity, duration }) {
const oncall = await getOnCallEngineer(new Date());
if (severity === 'critical' && duration > 5 * 60 * 1000) {
// Critical for >5 minutes: Aggressive escalation
await Promise.all([
postSlack({ channel: '#critical-incidents', text: 'CRITICAL ESCALATION' }),
sendSMS(oncall.phone),
makePhoneCall(oncall.phone),
pageBackup(oncall.backup)
]);
} else if (severity === 'critical') {
// Critical but recent: Gentle escalation
await Promise.all([
postSlack({ channel: '#critical-incidents' }),
sendSMS(oncall.phone)
]);
} else if (severity === 'warning') {
// Just log
await postSlack({ channel: '#alerts' });
}
}
Integração com PagerDuty#
Para uma gestão on-call sofisticada, integre com PagerDuty:
const PagerDutyClient = require('pagerduty');
async function pageOnCallVia PagerDuty(domain, severity) {
const client = new PagerDutyClient({
token: process.env.PAGERDUTY_TOKEN
});
// Create incident
const incident = await client.incidents.create({
type: 'incident_reference',
incident: {
type: 'incident',
title: `${domain} is down`,
body: {
type: 'incident_body',
description: `Website ${domain} is down. Response: Down. Severity: ${severity}`
},
urgency: severity === 'critical' ? 'high' : 'low',
service: {
id: process.env.PAGERDUTY_SERVICE_ID,
type: 'service_reference'
}
}
});
console.log(`Created PagerDuty incident: ${incident.id}`);
}
Confirmação e handoff#
Padrões de confirmação#
O engenheiro on-call precisa confirmar o incidente:
// Via Slack reaction
async function waitForSlackAcknowledgment(messageId, maxWait) {
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
// Poll for reactions
const reactions = await getSlackMessageReactions(messageId);
if (reactions.includes('white_check_mark')) {
return true; // Acknowledged
}
await sleep(10 * 1000); // Check every 10 seconds
}
return false; // Not acknowledged within max wait
}
// Via SMS
async function waitForSmsAcknowledgment(phone, maxWait) {
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
// Poll SMS responses
const responses = await getSmsResponses(phone);
if (responses.some(m => m.text.toUpperCase().includes('OK'))) {
return true; // Acknowledged
}
await sleep(5 * 1000); // Check every 5 seconds
}
return false; // Not acknowledged
}
Handoff entre times#
Quando um engenheiro on-call precisa passar o bastão para outro:
async function handoffIncident(incident, fromEngineer, toEngineer) {
// Update incident
incident.assignedTo = toEngineer;
incident.handoffAt = new Date();
await incident.save();
// Notify both
await sendMessage({
to: fromEngineer.slack,
text: `Handing off ${incident.domain} to ${toEngineer.name}`
});
await sendMessage({
to: toEngineer.slack,
text: `Taking over incident: ${incident.domain}. See: ${incident.dashboard}`
});
// Update status page
await updateStatusPage({
message: `Working with ${toEngineer.name}'s team on investigation`
});
}
Medindo a eficácia do escalonamento#
Acompanhe as métricas de escalonamento:
async function analyzeEscalationMetrics() {
const incidents = await Incident.find({
createdAfter: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) // Last 30 days
});
const metrics = {
totalIncidents: incidents.length,
avgTimeToAcknowledgment: calculateAvg(
incidents.map(i => i.acknowledgedAt - i.alertedAt)
),
avgTimeToEscalation: calculateAvg(
incidents.map(i => i.escalatedAt - i.alertedAt)
),
escalationRate: incidents.filter(i => i.escalatedAt).length / incidents.length,
avgMTTR: calculateAvg(
incidents.map(i => i.resolvedAt - i.alertedAt)
)
};
console.log('Escalation Metrics (Last 30 days):');
console.log(`Total Incidents: ${metrics.totalIncidents}`);
console.log(`Avg Time to Acknowledgment: ${metrics.avgTimeToAcknowledgment / 60}m`);
console.log(`Escalation Rate: ${(metrics.escalationRate * 100).toFixed(1)}%`);
console.log(`Avg MTTR: ${metrics.avgMTTR / 60}m`);
}
Erros comuns de escalonamento#
Erro 1: fadiga de alertas levando ao descarte#
Problema: alertas demais → o time para de responder → problemas reais passam despercebidos
Solução: use limiares rigorosos. Acione apenas para problemas realmente críticos.
Erro 2: escalonamento agressivo demais#
Problema: acionar o time inteiro em todo incidente → burnout → as pessoas saem
Solução: escalone gradualmente. Dê 5 minutos ao primário antes de acionar o backup.
Erro 3: escalonamento lento demais#
Problema: incidente crítico passa despercebido por 30 minutos → impacto enorme
Solução: para incidentes críticos, escalone em até 2-5 minutos.
Erro 4: sem processo de handoff#
Problema: o primário on-call não sabia que estava recebendo o bastão → caos
Solução: comunique handoffs explicitamente via Slack/e-mail.
Resumo: checklist de configuração de escalonamento#
- Defina os tiers de severidade dos incidentes (Crítico/Aviso/Info)
- Crie um cronograma de rotação on-call
- Defina os tempos de escalonamento (2 min → 5 min → 10 min → todos)
- Configure os canais de escalonamento (Slack → SMS → telefone → time inteiro)
- Configure roteamento por horário do dia
- Roteamento por domínio/dono do time
- Roteamento por tipo de incidente (banco de dados vs API vs e-mail)
- Integre com PagerDuty (se aplicável)
- Configure mecanismos de confirmação (reação no Slack, resposta de SMS)
- Defina os procedimentos de handoff
- Acompanhe as métricas de escalonamento
- Revisão mensal da eficácia do escalonamento
Comece hoje#
Comece simples: só Slack + SMS. Adicione complexidade (PagerDuty, roteamento condicional) conforme o volume de incidentes cresce.
Documente sua política de escalonamento na wiki do time. Compartilhe com todos os membros do time. Teste trimestralmente para garantir que tudo continua funcionando.
Sua política de escalonamento é a diferença entre "incidente resolvido em 5 minutos" e "indisponibilidade durou 3 horas". Invista em acertar isso.
Monitor Your Website Before It Goes Down
Get uptime monitoring, SSL tracking, domain expiry alerts, and email health checks. Free plan — no credit card required.
Start Monitoring FreeArtigos relacionados
Webhooks e Integrações de Monitoramento de Uptime: Crie Fluxos Personalizados
Conecte o monitoramento de uptime aos seus sistemas via webhooks. Guia completo de automação de incidentes, notificações personalizadas e padrões de integração.
Estudo de Caso: Como o Monitoramento de Uptime Salvou US$ 500 mil em Receita Perdida
Exemplo real de como o monitoramento proativo de uptime evitou um impacto catastrófico no negócio. Aprenda com a história de resposta a incidentes de uma.
Como integrar monitoramento de uptime com o Slack: guia de alertas em tempo real
Configure alertas do Slack para downtime em 10 minutos. Envie incidentes para #alerts e reduza o tempo de resposta de 30 minutos para 60 segundos.