O mínimo viável cabe em duas rotas: um /health para liveness e readiness, e um /metrics no formato Prometheus. Em Node, prom-client resolve com pouca cola.
Parceiro --> /webhook --> Fila --> Worker --> API externa
| | |
metricas metricas metricas
\ | /
---> /metrics ---> Prometheus --> Alertas// metrics.js
const client = require('prom-client');
const register = new client.Registry();
client.collectDefaultMetrics({ register });
const httpDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'Latencia das requisicoes HTTP',
labelNames: ['route', 'status'],
buckets: [0.05, 0.1, 0.3, 0.5, 1, 2, 5],
});
const webhookErrors = new client.Counter({
name: 'webhook_errors_total',
help: 'Total de erros no processamento do webhook',
labelNames: ['reason'],
});
const queueDepth = new client.Gauge({
name: 'queue_depth',
help: 'Mensagens pendentes na fila',
});
const queueOldestAge = new client.Gauge({
name: 'queue_oldest_message_age_seconds',
help: 'Idade da mensagem mais antiga na fila',
});
register.registerMetric(httpDuration);
register.registerMetric(webhookErrors);
register.registerMetric(queueDepth);
register.registerMetric(queueOldestAge);
module.exports = { register, httpDuration, webhookErrors, queueDepth, queueOldestAge };
// server.js
const express = require('express');
const { register, httpDuration } = require('./metrics');
const app = express();
// /health: liveness + readiness em um lugar
app.get('/health', async (req, res) => {
const checks = { fila: await pingQueue(), banco: await pingDb() };
const healthy = Object.values(checks).every(Boolean);
res.status(healthy ? 200 : 503).json({ status: healthy ? 'ok' : 'degraded', checks });
});
// /metrics: exposicao no formato Prometheus
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
// middleware para medir latencia por rota e status
app.use((req, res, next) => {
const end = httpDuration.startTimer({ route: req.path });
res.on('finish', () => end({ status: res.statusCode }));
next();
});