Bulkhead Pattern no Node.js isola recursos para impedir que a falha ou lentidão de uma dependência consuma toda a capacidade da aplicação. O nome vem dos compartimentos de navios: um vazamento em uma seção não deve afundar a embarcação inteira.
Em serviços Node.js, o padrão pode separar pools de conexão, filas de concorrência, Worker Threads, limites por rota ou capacidade por cliente.
O problema do recurso compartilhado
Imagine que pedidos, relatórios e notificações usam o mesmo pool HTTP com 100 conexões. Se relatórios ficarem lentos, podem ocupar todas as conexões e impedir pedidos críticos de avançar.
Separando pools por dependência
import { Pool } from 'undici';
const paymentsPool = new Pool('https://payments.internal', {
connections: 20
});
const reportsPool = new Pool('https://reports.internal', {
connections: 5
});Cada dependência possui capacidade própria. O serviço de relatórios não consegue esgotar o pool de pagamentos.
Fila de concorrência
class Semaphore {
#active = 0;
#queue = [];
constructor(limit) {
this.limit = limit;
}
async run(task) {
if (this.#active >= this.limit) {
await new Promise((resolve) => this.#queue.push(resolve));
}
this.#active++;
try {
return await task();
} finally {
this.#active--;
this.#queue.shift()?.();
}
}
}
const reports = new Semaphore(4);O semáforo limita quantas operações avançam ao mesmo tempo. Em produção, acrescente tamanho máximo de fila e timeout de espera.
Fail fast quando a fila está cheia
Esperar indefinidamente apenas desloca a falha. Quando a capacidade foi atingida, rejeite cedo com erro controlado ou resposta 503.
if (queue.size >= MAX_QUEUE) {
throw new Error('CAPACITY_EXCEEDED');
}Bulkhead por rota
Rotas de exportação, upload ou processamento pesado merecem limites separados. Uma rota cara não deve degradar endpoints simples de leitura.
Bulkhead por tenant
Em sistemas multi-tenant, limite concorrência por organização. Isso evita que um cliente ruidoso consuma toda a capacidade compartilhada. Consulte Multi-Tenancy no Node.js.
Worker Threads como isolamento
Trabalho CPU-bound deve ser movido para pools de workers. Defina quantidade máxima e fila limitada. Veja Worker Threads no Node.js.
Bulkhead e circuit breaker
Os padrões resolvem problemas diferentes. O bulkhead limita o dano; o circuit breaker interrompe chamadas quando a dependência está falhando. Use ambos quando necessário.
Consulte Circuit Breaker no Node.js.
Bulkhead e timeout
Limite de concorrência sem timeout ainda permite recursos presos por muito tempo. Defina prazo para conexão, headers, corpo e espera na fila.
Dimensionamento
Não escolha números arbitrários. Meça latência, throughput, CPU, memória e limite real da dependência. Pela Lei de Little, concorrência tende a crescer com taxa de chegada e tempo médio de serviço.
Prioridades
Nem todas as operações têm o mesmo valor. Pedidos interativos podem receber capacidade reservada, enquanto relatórios assíncronos usam fila de baixa prioridade.
Observabilidade
Monitore por compartimento:
- concorrência ativa;
- tamanho da fila;
- tempo de espera;
- rejeições por capacidade;
- timeouts;
- taxa de sucesso;
- uso de CPU e memória.
Graceful shutdown
Ao encerrar, pare de aceitar novas tarefas e aguarde as operações em andamento dentro de um prazo. Não abandone itens silenciosamente.
Erros comuns
- uma fila global para tudo;
- fila sem limite;
- limites altos demais;
- não medir rejeições;
- isolar conexões, mas compartilhar workers saturados;
- repetir operações rejeitadas sem jitter;
- não reservar capacidade para rotas críticas.
Conclusão
Bulkhead Pattern no Node.js protege a aplicação ao dividir capacidade entre dependências, rotas e tipos de trabalho. O padrão funciona melhor com filas limitadas, timeouts, circuit breakers e métricas por compartimento.
Comece isolando recursos de maior risco e ajuste limites com dados reais. Consulte a documentação de Worker Threads e a documentação do Undici.



