Documentação / Worker: PostgreSQL pooling e conexões

Worker: PostgreSQL pooling e conexões

Entrar

Worker: PostgreSQL pooling e conexões

Visão geral

Cada processo do worker (container/replica) usa um único Prisma Client com um connection pool para o Postgres. O número de sessões TCP no servidor é aproximadamente:

réplicas do worker + réplicas da API + jobs adicionais × conexões por pool

Use PgBouncer (modo transaction) ou o pooler do provedor se precisar de muitas instâncias de aplicação com um teto baixo de conexões reais no Postgres.

DATABASE_URL (Prisma)

Parâmetros úteis na query string (PostgreSQL):

| Parâmetro | Efeito | |---------------------|--------| | connection_limit | Máximo de conexões no pool por processo (ex.: 12). | | pool_timeout | Segundos à espera de uma conexão livre do pool. |

Exemplo (acrescentar ao URL existente, respeitando ? vs &):

postgresql://user:pass@host:5432/db?schema=public&connection_limit=12&pool_timeout=20

A API (apps/fullstack ou equivalente) e o worker somam conexões se apontarem ao mesmo Postgres sem pooler. Ajuste connection_limit em cada serviço para o tráfego esperado (ex.: API com mais, worker com teto coerente com a concorrência BullMQ documentada abaixo).

Concorrência BullMQ no worker

Variáveis opcionais (ver apps/worker/src/worker-bull-concurrency.ts):

  • WORKER_BULL_CONCURRENCY_FREE_PLAN_RENEWAL (default 5)
  • WORKER_BULL_CONCURRENCY_STRIPE_SUB_BOUNDARY (default 3)
  • WORKER_BULL_CONCURRENCY_PIX_SUBSCRIPTIONS (default 5)
  • WORKER_BULL_CONCURRENCY_DATA_RETENTION (default 1)
  • WORKER_BULL_CONCURRENCY_PILOT_INSTANCE_HEALTHCHECK (default 1)
  • WORKER_BULL_CONCURRENCY_WHATSAPP_INSTANCE_VALIDATE (default 2)
  • WORKER_BULL_CONCURRENCY_RECOVERY_SWEEP (default 1)
  • WORKER_BULL_CONCURRENCY_LABELS (default 5)

Filas por instância WhatsApp usam concurrency: 1 por fila. Reduza as variáveis acima se o pool estiver a esgotar (pool_timeout / filas de espera no Prisma).

Pilot instance healthcheck (restarts sequenciais)

O job processAllInstancesHealthcheck avalia instâncias OPEN uma a uma; quando várias precisam de restart (Evolution V2 / GO), os restarts executam em sequência dentro da mesma execução do job (não em paralelo). O job pode demorar mais se houver muitas instâncias a reiniciar; WORKER_BULL_CONCURRENCY_PILOT_INSTANCE_HEALTHCHECK continua a limitar quantos jobs deste tipo correm em paralelo entre si por processo.

Message reconcilers (locks Redis e batches)

Os reconcilers de fila QUEUED / SENT / entrega / READ usam locks NX no Redis (ver message-reconcile-lock.ts e message-reconciler-schedule.ts).

| Variável | Efeito | |----------|--------| | MESSAGE_RECONCILER_PER_TYPE_LOCKS | 1 ou true: lock por tipo (ps:reconciler:lock:queued, :sent, :delivered, :retries) e reconcilers podem correr em paralelo. Omitido: cadeia num único lock (ps:reconciler:lock:chain) — queuedsentdelivered no timer horário; na arranque inclui também retries. | | MESSAGE_RECONCILER_LOCK_TTL_MS | TTL do lock em ms (mín. 10s, máx. 600s). Default 180000 (3 min) para acomodar a cadeia. | | MESSAGE_RECONCILER_LOG_LOCK_MISSES | 1 / true: debug quando SET NX falha (outro processo detém o lock). | | MESSAGE_RECONCILER_BATCH_SIZE | Linhas por batch (default 200, máx. 5000). | | MESSAGE_RECONCILER_MAX_BATCHES | Batches por execução (default 5, máx. 100). |

Intervalos existentes: MESSAGE_RECONCILER_INTERVAL_MS, SENT_DELIVERY_RETRY_INTERVAL_MS (ver bootstrap/start.ts).

Cache da lista de instâncias (menos leituras)

  • WORKER_INSTANCE_NAMES_LIST_CACHE_TTL_MS — TTL do cache Redis da lista de nomes de instância (default 45000). Use 0 para desativar e consultar sempre o banco.
  • O cache é invalidado no canal Redis whatsapp:instance:open (ver list-desired-instance-names.ts).

Observabilidade

  • pg_stat_activity no Postgres para contar sessões por aplicação.
  • Logs Prisma query em development no pacote @pilot-status/database (packages/database/src/index.ts).

Sessões zumbi e “too many clients already”

Quando max_connections está esgotado, novas sessões (incluindo psql ou o script abaixo) recebem FATAL: sorry, too many clients already. Libere slots antes de administrar o banco: por exemplo, pausar temporariamente o worker ou o frontend na Ilumin, ou reiniciar um serviço que segure pool grande.

Script no repositório

Com DATABASE_URL apontando para o banco alvo:

cd packages/database
npx tsx scripts/postgres-zombie-cleanup.ts
  • Por defeito só inspeciona (pg_stat_activity, contagens por state, max_connections).
  • --terminate — executa pg_terminate_backend em sessões idle in transaction / idle in transaction (aborted) com state_change mais antigo que 10 minutos (ajustável com --idle-minutes=N).
  • --apply-role-timeouts — tenta ALTER ROLE <current_user> SET idle_in_transaction_session_timeout = '5min' (requer permissão no papel atual).

Exemplo:

DATABASE_URL="postgresql://user:pass@host:5432/pilot_status?schema=public" npx tsx scripts/postgres-zombie-cleanup.ts --terminate --idle-minutes=10

Não use --terminate em massa sobre estado idle sem rever application_name: pools Prisma mantêm conexões idle saudáveis.

Postgres (SQL manual)

Os mesmos passos descritos no plano interno: SELECT em pg_stat_activity, depois SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE ... com critérios conservadores. Cliente psql não aceita o parâmetro de query schema=public do Prisma — use URL sem esse parâmetro e SET search_path TO public, ou use o script com URL Prisma completa.

Ilumin e segredos

ilumin.yml e apps/worker/ilumin.yml usam DATABASE_URL: ${DATABASE_URL} / - DATABASE_URL=${DATABASE_URL}. Configure o valor completo (com connection_limit e pool_timeout adequados ao serviço) no painel Ilumin, não no Git.