Regras de Segurança para Migração
Jobs de deploy de migração devem falhar rapidamente em contenção de bloqueio e nunca bloquear o tráfego da aplicação de forma ilimitada. Codifique timeouts e DDL faseado nas regras da equipe.
Receita
-- Primeiras linhas de cada arquivo de migração de produção
SET lock_timeout = '5s';
SET statement_timeout = '0'; -- permite CONCURRENTLY longos
SET idle_in_transaction_session_timeout = '60s';# Wrapper do job de deploy
flyway migrate || { echo "migração falhou - aplicação NÃO foi atualizada"; exit 1; }Quando usar isso: Template de CI para migrações SQL, retrospectiva de incidentes após acúmulo de bloqueios, padronização Flyway/Liquibase.
Exemplo de Trabalho
SET lock_timeout = '3s';
BEGIN;
CREATE TABLE app.new_feature (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name text NOT NULL
);
COMMIT;-- Arquivo separado: executeInTransaction=false (Flyway)
SET lock_timeout = '10s';
SET statement_timeout = '0';
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_new_feature_name
ON app.new_feature (name);Regras do pipeline de deploy:
- Falha na migração bloqueia o deploy da aplicação (mesmo estágio do pipeline ou anterior)
- Alerta sobre
lock timeoutnos logs de migração - Verificação de índice inválido pós-deploy:
SELECT indexrelid::regclass
FROM pg_index
WHERE NOT indisvalid;Mergulho Profundo
Matriz de Timeout
| Configuração | Padrão de Migração | Propósito |
|---|---|---|
lock_timeout | 3s-10s | Abortar se não conseguir adquirir o bloqueio |
statement_timeout | 0 para CONCURRENTLY; 30s para DDL de teste | Matar instruções descontroladas |
idle_in_transaction_session_timeout | 60s | Prevenir sessões de migração travadas |
Ordem de DDL Ciente de Bloqueio
ADD COLUMNnullable (rápido)- Preenchimento de dados (em lotes, job separado)
CREATE INDEX CONCURRENTLYADD CONSTRAINT NOT VALIDVALIDATE CONSTRAINTfora do picoDROP COLUMNsomente após fase de contrato da aplicação
Regras do Job de Deploy
- Conexão única do migrador (não Flyway paralelo no mesmo banco de dados)
- Nenhuma migração durante manutenção sobreposta que também reinicia o Postgres
- Teste de fumaça de diferença de esquema após migrar
- Roll forward documentado; nenhuma cirurgia na tabela de histórico
Armadilhas
- Zero lock_timeout - A migração espera horas por uma consulta analítica de fim de semana. Correção: Sempre defina
lock_timeoutexplícito. - Mesmo statement_timeout para todo SQL - CONCURRENTLY morto em 30s em uma tabela enorme. Correção: Divida arquivos; desabilite txn para executores longos.
- Sucesso da migração + índice inválido - Consultas da aplicação ignoram índice quebrado, tempestade de varredura sequencial. Correção: Consulta de validade pós-deploy em CI.
- Deploy da aplicação antes da migração - Aplicação antiga encontra coluna ausente. Correção: Migrar primeiro ou expandir ordem compatível.
- Executando migrações do laptop - Ignora a verificação de concessões da CI. Correção: Migração de produção apenas via pipeline.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Ferramenta de alteração de esquema online (classe gh-ost) | Hábitos do MySQL | CONCURRENTLY nativo do Postgres é suficiente |
| Janela de manutenção | Inicialização de tabela pequena | Serviço com SLA |
| Runbook manual de DBA | Tarefa única regulamentada | Ambiente de deploy contínuo |
FAQs
Tentar novamente após timeout de bloqueio?
Sim, com backoff exponencial no job de deploy - após confirmar que nenhum passo parcial não transacional deixou objetos INVÁLIDOS.
lock_timeout no código da aplicação também?
Aplicações usam timeouts menores para consultas; migrações usam role e job separados - não copie valores cegamente.
Quem define timeouts - DBA ou dev?
DBA publica template; dev copia em cada arquivo de migração via linter ou snippet.
Relacionados
- DDL de Zero Downtime - DDL faseado
- Melhores Práticas de Migração - lista completa
- Estratégia de Rollback - ADR somente para frente
Versões do Stack: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, e PostGIS 3.5+.