Evitar que n8n sobrecarregue PostgreSQL quando execuções de workflow aumentam repentinamente

Estou executando múltiplos fluxos de trabalho do n8n que leem e atualizam o PostgreSQL. Durante picos de tráfego, muitas execuções começam ao mesmo tempo e o PostgreSQL começa a mostrar alto uso de CPU e muitas conexões ativas.
Atualmente estou consultando assim: SELECT id, status
FROM orders
WHERE status = ‘pending’
ORDER BY created_at
LIMIT 100;
Estou considerando limitar a concorrência do n8n e adicionar índices: CREATE INDEX orders_pending_idx
ON orders (status, created_at);
Você priorizaria limites de concorrência do n8n, índices melhores, pooling de conexões, agrupamento em lotes, ou uma combinação desses?

Descreva o problema/erro/pergunta

Qual é a mensagem de erro (se houver)?

Por favor, compartilhe seu fluxo de trabalho

(Selecione os nós na sua tela e use os atalhos de teclado CMD+C/CTRL+C e CMD+V/CTRL+V para copiar e colar o fluxo de trabalho.)

Compartilhe a saída retornada pelo último nó

Informações sobre sua configuração do n8n

  • Versão do n8n:
  • Banco de dados (padrão: SQLite):
  • Configuração n8n EXECUTIONS_PROCESS (padrão: own, main):
  • Executando n8n via (Docker, npm, n8n cloud, aplicativo desktop):
  • Sistema operacional:

Oi @Decoure_Ryan, enquanto aguarda uma resposta, aqui estão algumas coisas que podem ajudar:

Recursos sugeridos

Correspondência automática com sua pergunta.

Docs:

Fórum:

@anon45958619, @zenithflare, @Websensepro - vocês já ajudaram com problemas similares, podem dar uma olhada?

Sugerido automaticamente pelo bot da comunidade n8n. É um piloto - compartilhe seu feedback aqui.

Oi @Decoure_Ryan Eu resolveria isso com uma combinação de controle de concorrência do n8n, indexação adequada do PostgreSQL, batching e connection pooling.

O principal é não deixar o n8n enviar mais trabalho para o PostgreSQL do que o banco de dados consegue lidar confortavelmente

Controle a concorrência do n8n

Se centenas de workflows começarem ao mesmo tempo, o PostgreSQL pode ficar rapidamente sobrecarregado. Defina um limite de concorrência razoável e aumente-o gradualmente enquanto monitora o desempenho.

Torne a consulta eficiente

Seu índice é um bom começo:

CREATE INDEX orders_pending_idx
ON orders (status, created_at);

Isso ajuda o PostgreSQL a encontrar pedidos pendentes muito mais rápido.

Use lotes menores

Em vez de puxar milhares de registros de uma vez:

SELECT id, status
FROM orders
WHERE status = ‘pending’
ORDER BY created_at
LIMIT 100;

Processe um lote gerenciável e depois busque o próximo.

Use connection pooling

Se você tem muitas execuções do n8n simultâneas, o connection pooling ajuda a evitar que o PostgreSQL seja inundado com conexões.

Oi @Decoure_Ryan

Para resolver seus problemas de desempenho imediatos, priorize adicionar o índice composto em (status, created_at). Sua consulta atual provavelmente dispara uma varredura completa da tabela, o que causa picos de CPU conforme a tabela cresce. Implementando este índice, o PostgreSQL pode localizar instantaneamente linhas “pending” e recuperá-las na ordem correta sem o custo computacional pesado de uma classificação manual, fornecendo o alívio mais rápido para o uso da CPU.

Para resolver o erro “too many connections”, implemente um connection pooler como PgBouncer entre n8n e sua instância PostgreSQL. Como o modelo de alta concorrência do n8n tenta abrir uma nova conexão para muitas execuções simultâneas, pode rapidamente esgotar o limite de conexões do banco de dados. Usando PgBouncer no modo “transaction pooling”, centenas de fluxos de trabalho do n8n podem compartilhar um pool muito menor e estável de conexões reais de banco de dados, reduzindo significativamente a sobrecarga e prevenindo erros de conexão.

Por fim, implemente guardrails arquitetônicos combinando limites de concorrência do n8n com processamento em lote. Limitar o número de execuções simultâneas garante que, mesmo durante picos massivos de tráfego, a pressão total no banco de dados permaneça dentro de um intervalo previsível. Para escalabilidade de longo prazo, faça a transição de muitos fluxos de trabalho pequenos e frequentes para um fluxo de trabalho “mestre” que busca e processa lotes maiores de dados de uma vez, o que minimiza o número total de requisições ao banco de dados e maximiza a eficiência.

Oi @Decoure_Ryan

Adicionando

Prioritize os correções nesta ordem:

  1. Use SKIP LOCKED e um índice parcial:

    SELECT id, status
    FROM orders
    WHERE status = 'pending'
    ORDER BY created_at
    LIMIT 100
    FOR UPDATE SKIP LOCKED;
    
    
    CREATE INDEX orders_pending_idx 
    ON orders (created_at) 
    WHERE status = 'pending';
    
    
  2. Adicione pool de conexões:
    Coloque PgBouncer (em modo de transação) na frente do PostgreSQL ou limite o tamanho do pool de conexões do n8n (DB_POSTGRESDB_POOL_SIZE=10).

  3. Limite a concorrência de execução:
    Se estiver usando Queue Mode (Redis), defina N8N_CONCURRENCY_PRODUCTION_LIMIT=10 nos seus workers. Se estiver em instância única, processe registros sequencialmente em lotes em vez de gerar dezenas de execuções paralelas.

Espero que ajude.

Oi @Decoure_Ryan
Se o n8n mantiver seus próprios dados nessa mesma instância do Postgres, parte do pico é o n8n escrevendo sobre si mesmo. Toda execução em produção insere uma linha em execution_entity e toda a carga útil da execução em execution_data, e esse volume de escrita acompanha a contagem de execuções independentemente de como a consulta de pedidos é otimizada. Verifique com SELECT pg_size_pretty(pg_total_relation_size('execution_data')); e se essa tabela dominar, pare de salvar execuções bem-sucedidas e reduza a retenção:

EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
EXECUTIONS_DATA_MAX_AGE=72