
Adicionar um orquestrador externo como Temporal ou AWS↳AWS20 conteúdosE-mails de verificação com AWS SES + Lambda (Node.js) e Terraform: do zero ao envioDevSecOps · out 2025Codex na AWS: chegada do agente da OpenAI à nuvem da AmazonDevSecOps · abr 2026Salesforce e AWS ampliam colaboração em IA, CRM e marketplaceDevSecOps · nov 2023Ver tudo em DevSecOps → Step Functions costuma ser o conselho padrão para quem precisa de execução durável (aquela ideia de checkpoint contínuo do estado, tipo autosave de videogame para código de backend). Mas um artigo publicado na InfoQ por Raman Varma, do time do Kestrel Workflows, argumenta que, se você já roda Postgres↳PostgreSQL11 conteúdosPostgreSQL via SSL com GolangData · abr 20195 itens legais sobre data types do PostgreSQLData · mar 20195 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data → como sistema de registro, não precisa de mais nada para isso. A tese é direta: durabilidade é fundamentalmente uma questão de gravar estado em um banco durável, então por que não fazer do próprio Postgres o orquestrador?
O cenário que motivou a decisão é reconhecível para qualquer time de infra: um workflow que dispara em cima de uma workload do Kubernetes falhando, roda uma análise de causa raiz com IA↳Inteligência artificial440 conteúdosUX e IA: Transformando Experiências Digitais com Inteligência ArtificialProduto & UX · jan 2025MCP: O que é e por que você vai ouvir falar disso em breve?AI · jul 2025IA generativa e a urgência de reconstruir nossa relação com a verdadeAI · jun 2025Ver tudo em AI →, gera um fix, espera aprovação humana no Slack e abre um pull request via GitOps. Se o pod for reescalonado no meio disso (e no Kubernetes vai ser), perder a execução não é opção.
Por que o time abriu mão do orquestrador externo
O artigo lista o custo real de plugar um orquestrador dedicado, e é aqui que a discussão fica concreta para quem constrói:
- Mais um sistema stateful para deployar, proteger, monitorar e atualizar, sentado no caminho crítico de todo workflow (ou seja, ponto único de falha).
- Nova superfície de segurança e auditoria: no caso do Kestrel, os payloads dos steps incluem topologia de infraestrutura, código-fonte e logs, que passariam a trafegar para um sistema externo.
- Modelo de dados próprio, normalmente um key-value otimizado para estado de workflow, o que torna análise ad-hoc menos direta do que uma query relacional.
A conclusão do autor é que já haviam investido pesado em fazer o Postgres performar em escala, então adicionar um orquestrador seria pagar duas vezes pela mesma garantia de durabilidade.
A cláusula que segura tudo: SKIP LOCKED
No Kestrel não existe processo orquestrador. Cada servidor de aplicação roda uma biblioteca de workflow embutida e fala direto com o Postgres. Todo gatilho (de alertas do PagerDuty a webhooks do GitHub) insere uma linha numa tabela workflow_executions, e os servidores fazem polling nessa tabela para reivindicar trabalho.
O truque que torna isso seguro é uma cláusula só:
SELECT id, input
FROM workflow_executions
WHERE status = 'enqueued'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;O FOR UPDATE SKIP LOCKED trava as linhas que um worker pega e manda os demais workers pularem em vez de bloquear. Dois servidores podem varrer a mesma tabela ao mesmo tempo e nunca entregar o mesmo workflow para dois executores. Sem broker, sem eleição de líder, sem locks no Redis com TTL. Vale notar que o padrão não é exclusivo do Postgres: MySQL 8.0+, MariaDB 10.6+ e Oracle também suportam SKIP LOCKED, enquanto Db2 e SQL Server oferecem mecanismos equivalentes.
O artigo faz três ressalvas honestas para produção: a transação de claim tem que ser minúscula (só trava, muda o status e commita, nunca segura a transação enquanto o step roda); o LIMIT pode ser maior que 1 para pegar lotes, mas aumenta o raio de dano se o worker morrer; e o SKIP LOCKED não preserva FIFO sob contenção, então quem precisa de ordem estrita não deveria usar esse padrão.
Idempotência como constraint, não como código
Os checkpoints de cada step vão para uma tabela operation_outputs com chave primária (execution_id, step_id). O worker grava o resultado com um upsert que nunca sobrescreve:
INSERT INTO operation_outputs (execution_id, step_id, output)
VALUES ($1, $2, $3)
ON CONFLICT (execution_id, step_id) DO NOTHING
RETURNING output;Se um worker em recuperação re-executa um step que já commitou, a constraint de unicidade impede o checkpoint duplicado. Em vez de rodar o efeito colateral de novo, o worker lê o checkpoint existente e devolve o resultado anterior. É o banco, e não o código da aplicação, garantindo idempotência. É um exemplo bonito de expressar um invariante de sistema distribuído como constraint relacional em vez de escrever a contabilidade na mão.
Recovery com lease e sweeper
A falha interessante é quando um worker reivindica uma execução, coloca em running e morre (OOM kill, drain de nó, eviction de pod). A linha fica presa em running sem dono vivo. A solução são as colunas de lease: o worker que possui uma execução dá heartbeat num intervalo, empurrando lease_expires para frente. Um sweeper periódico devolve para a fila tudo que expirou:
UPDATE workflow_executions
SET status = 'enqueued', owner_id = NULL
WHERE status = 'running'
AND lease_expires < now();A duração do lease é um tradeoff explícito: curto demais e um worker lento (mas vivo) tem o trabalho roubado; longo demais e o recovery após crash atrasa. Aqui a idempotência dos checkpoints é o que dá liberdade para usar leases agressivos, porque um sweep falso-positivo causaria no máximo trabalho duplicado, não efeito colateral em dobro.
Sleeps e aprovações humanas que sobrevivem a restart
Esperar aprovação humana no Slack, que pode levar de duas horas a duas semanas, também é durável. Em vez de uma goroutine rezando para o pod viver o suficiente, é só uma linha numa tabela workflow_waits com um timestamp wake_at. A execução se coloca em waiting, e um sweeper re-enfileira o que já venceu. Não importa o tamanho da janela de espera: o custo é sempre o mesmo, uma linha.
Observabilidade e escala: onde a conta fecha
Como cada workflow e cada step é uma linha, monitoramento vira SQL puro. Quer todas as execuções que deram erro no mês? SELECT * FROM workflow_executions WHERE created_at > NOW() - INTERVAL '1 month' AND status = 'error'. Dá para ir além e cruzar execuções com steps e aprovações para responder "quais fixes foram rejeitados e em qual step?". Com orquestradores externos, esse tipo de query relacional exige exportar o estado do key-value para um sistema de analytics separado.
Sobre escala, o autor afirma que uma única instância aguentou dezenas de milhares de workflows por segundo sem read replicas nem Citus, escalando throughput com workers stateless. E cita os pontos de atenção reais: pressão de conexão (a recomendação é PgBouncer em transaction pooling na frente, com backoff e jitter no polling) e dead tuples/bloat em tabela de fila de alto churn (tuning de autovacuum, índices parciais e particionamento das execuções concluídas para longe da fila viva).
O próprio artigo é honesto sobre o limite: se você precisa de fan-out para milhares de workers e latência de dispatch sub-milissegundo, um Temporal ainda é a escolha arquitetural melhor. O Kestrel roda pipelines de automação I/O-bound, que duram de segundos a horas e precisam de concorrência modesta, e para esse perfil o Postgres não é concessão, é encaixe.
O que muda para quem constrói no Brasil
Para startup e time pequeno, o recado prático é que uma capacidade que muita gente presume exigir um serviço externo pode sair de um banco que você já opera, paga e sabe manter. Menos um sistema stateful no caminho crítico significa menos infra para provisionar, menos superfície de auditoria (LGPD↳LGPD14 conteúdosComo utilizar a LGPD com o objetivo de conformidade e inovação?Gestão Dev & TI · out 2021LGPD coloca pressão inédita nos responsáveis pela tecnologia das empresasData · ago 2021Proteção de dados: LGPD é sancionada e começa a valerData · set 2020Ver tudo em Gestão Dev & TI → agradece: nenhum payload de workflow sai do banco) e uma conta de nuvem que não ganha mais um componente. Confiabilidade e segurança colapsam numa dependência só, porque, se o Postgres cair, o resto do produto já caiu junto.
O ponto de partida honesto antes de replicar o padrão: avalie o perfil da sua carga. Se seus workflows são de automação I/O-bound com concorrência moderada, o desenho descrito é reproduzível hoje com SKIP LOCKED, constraints e um sweeper. Se você precisa de ordenação estrita, fan-out massivo ou dispatch sub-milissegundo, os próprios autores apontam a saída para o orquestrador dedicado.
Fonte: InfoQ
Este artigo foi escrito por Redação iMasters. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.










Comentários
Ninguém comentou ainda. Começa a conversa?