Noções Básicas de Resiliência
8 exemplos para você começar com Resiliência para backends Node.js - 6 básicos e 2 intermediários.
Busque em todas as páginas da documentação
8 exemplos para você começar com Resiliência para backends Node.js - 6 básicos e 2 intermediários.
fetch nativo e AbortSignal.timeout.Chamadas downstream travadas esgotam seu pool de conexões.
const response = await fetch("https://api.partner.com/data", {
signal: AbortSignal.timeout(5_000),
});AbortSignal.timeout disponível no Node 18+ - sem setTimeout manual.TimeoutError para 504 ou política de retentativa upstream.Relacionado: Timeouts em Todos os Lugares - matriz completa de timeouts
Não sirva tráfego com ambiente inválido.
import { z } from "zod";
const Env = z.object({
DATABASE_URL: z.string().url(),
PORT: z.coerce.number().default(3000),
});
export const env = Env.parse(process.env); // lança antes de iniciar()Relacionado: Noções Básicas de Configuração - parse de env com Zod
Informe ao Kubernetes se deve reiniciar ou parar de enviar tráfego.
app.get("/health", (_req, res) => res.json({ ok: true }));
app.get("/ready", async (_req, res) => {
try {
await db.query("SELECT 1");
res.json({ ready: true });
} catch {
res.status(503).json({ ready: false });
}
});Relacionado: Noções Básicas de Observabilidade - padrões de probe
Drene requisições HTTP em andamento antes de sair no deploy.
const server = app.listen(3000);
process.on("SIGTERM", () => {
server.close(() => {
logger.info({ event: "shutdown_complete" });
process.exit(0);
});
setTimeout(() => process.exit(1), 30_000).unref();
});server.close para de aceitar novas conexões; finaliza as ativas.terminationGracePeriodSeconds do k8s.Relacionado: Degradação Graciosa - modos de desativação de funcionalidades
POST sem chaves de idempotência pode cobrar em duplicidade.
async function safeGetWithRetry(url: string, attempts = 3): Promise<Response> {
for (let i = 0; i < attempts; i++) {
try {
const res = await fetch(url, { signal: AbortSignal.timeout(3_000) });
if (res.status < 500) return res;
} catch (err) {
if (i === attempts - 1) throw err;
}
await delay(100 * 2 ** i);
}
throw new Error("unreachable");
}Relacionado: Retentativas com Backoff - jitter e idempotência
Usuários e balanceadores de carga precisam de uma resposta dentro do SLA.
app.use((req, res, next) => {
const timer = setTimeout(() => {
if (!res.headersSent) {
res.status(504).json({ error: "Gateway Timeout" });
}
}, 30_000);
res.on("finish", () => clearTimeout(timer));
next();
});requestId para correlação.Relacionado: Timeouts em Todos os Lugares - timeouts de servidor
Pare de chamar uma dependência falha para permitir que ela se recupere.
let failures = 0;
const THRESHOLD = 5;
let openUntil = 0;
async function callBilling() {
if (Date.now() < openUntil) throw new Error("Circuit open");
try {
const result = await billingClient.charge();
failures = 0;
return result;
} catch (err) {
failures++;
if (failures >= THRESHOLD) openUntil = Date.now() + 30_000;
throw err;
}
}opossum em produção.Relacionado: Circuit Breakers - padrões com opossum
Um fornecedor lento não pode consumir todos os sockets.
import { Semaphore } from "async-mutex"; // ou pool customizado
const vendorSem = new Semaphore(10);
async function callVendor() {
const [, release] = await vendorSem.acquire();
try {
return await fetch(VENDOR_URL, { signal: AbortSignal.timeout(2_000) });
} finally {
release();
}
}Relacionado: Circuit Breakers - bulkhead com opossum
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026