Timeout Budget no Node.js define quanto tempo uma operação pode gastar do início ao fim e distribui esse prazo entre filas, conexões, chamadas externas e processamento. Em sistemas distribuídos, configurar um timeout independente em cada camada pode fazer a latência total ultrapassar o limite do usuário.
O conceito central é simples: existe um deadline absoluto. Cada etapa consulta o tempo restante e nunca recebe mais prazo do que ainda está disponível.
Timeout não é deadline
Timeout normalmente representa uma duração local, como “espere dois segundos”. Deadline representa um instante final. Quando uma requisição atravessa vários serviços, propagar o deadline preserva o orçamento restante.
Criando um deadline
function createDeadline(timeoutMs) {
const expiresAt = Date.now() + timeoutMs;
return {
remaining() {
return Math.max(0, expiresAt - Date.now());
},
expired() {
return Date.now() >= expiresAt;
}
};
}
const deadline = createDeadline(2_000);Usando AbortController
async function fetchWithDeadline(url, deadline) {
const remaining = deadline.remaining();
if (remaining === 0) throw new Error('DEADLINE_EXCEEDED');
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), remaining);
try {
return await fetch(url, { signal: controller.signal });
} finally {
clearTimeout(timer);
}
}O sinal interrompe a espera do cliente. Ainda assim, o serviço remoto pode continuar processando se não receber ou respeitar cancelamento.
Distribuindo o orçamento
Uma requisição com dois segundos não deve conceder dois segundos a cada dependência. Reserve tempo para serialização, filas e resposta ao cliente.
const total = 2_000;
const authBudget = 200;
const databaseBudget = 600;
const externalBudget = 800;
const responseReserve = 400;Esses valores devem ser derivados de métricas de latência, não apenas de opinião.
Propagando o deadline
Em chamadas internas, envie um header técnico com o instante final ou o tempo restante. Nunca aceite esse valor sem limites quando vier da internet.
headers: {
'x-deadline-ms': String(Date.now() + deadline.remaining())
}Serviços internos calculam o tempo restante e aplicam um teto configurado.
Retries consomem orçamento
Antes de repetir, confirme que existe tempo para backoff e uma nova tentativa. Um retry iniciado perto do deadline só aumenta carga e provavelmente falhará.
if (deadline.remaining() < minimumAttemptTime) {
throw new Error('DEADLINE_EXCEEDED');
}Veja Retry com Backoff no Node.js.
Timeout de conexão, headers e corpo
Uma única duração global pode esconder onde o tempo foi gasto. Diferencie:
- espera na fila;
- resolução DNS;
- conexão TCP/TLS;
- tempo até os headers;
- leitura do corpo;
- processamento local.
Banco de dados
Configure timeout de statement e de aquisição do pool. Não adianta limitar a query a um segundo se ela espera dez segundos por uma conexão.
await client.query(`SET LOCAL statement_timeout = '800ms'`);Filas internas
Registre quando a tarefa entrou na fila. Ao começar, verifique se ainda há orçamento. Itens expirados devem ser descartados ou respondidos com erro controlado, em vez de consumir CPU inutilmente.
Timeout e circuit breaker
Timeout detecta uma chamada lenta. Circuit breaker usa o histórico de falhas para evitar novas chamadas durante uma degradação. Consulte Circuit Breaker no Node.js.
Streaming
Streams longos podem usar timeout de inatividade em vez de prazo total rígido. Defina expectativas: tempo para iniciar, intervalo máximo sem bytes e duração máxima quando aplicável.
Observabilidade
Registre o orçamento inicial, tempo restante por etapa e motivo do cancelamento. Métricas úteis:
- deadlines excedidos;
- tempo em fila;
- latência por dependência;
- retries abandonados por falta de prazo;
- operações concluídas perto do limite.
Escolhendo o valor
Use requisitos do produto e percentis reais. Um endpoint interativo pode ter prazo menor do que uma exportação assíncrona. Defina SLO de latência e mantenha margem para picos.
Erros comuns
- somar vários timeouts independentes;
- não limitar espera no pool;
- iniciar retry sem tempo suficiente;
- propagar deadline não validado;
- cancelar no cliente sem interromper trabalho interno;
- usar o mesmo prazo para todas as rotas;
- não medir em qual etapa ocorreu o estouro.
Conclusão
Timeout Budget no Node.js transforma latência em um recurso finito. Ao propagar um deadline e consumir apenas o tempo restante, a aplicação evita filas intermináveis, retries inúteis e respostas tardias.
Combine AbortController, limites de pool, timeouts de banco e métricas por etapa. Consulte a documentação de AbortController do Node.js e a documentação do Undici.



