Separa migrations do boot do web, com uma etapa de release - #93
Merged
Merged
Conversation
bin/docker-entrypoint roda db:prepare antes do Puma toda vez que o container sobe. É o que faz `docker compose up --build` funcionar de primeira, e continua sendo o default — mas passou a ser desligável com DB_PREPARE_ON_BOOT=false, que é o que um deploy de verdade deve fazer, rodando as migrations numa etapa de release antes de subir as réplicas. Sobre a premissa da issue, que falava em "todas as réplicas tentam preparar o banco ao mesmo tempo": o schema nunca esteve em risco. As migrations do Rails pegam um advisory lock no Postgres (verificado em activerecord-8.1.3.1: Migrator#with_advisory_lock). O que acontece de verdade é pior de um jeito diferente, e vale a correção: o lock é obtido com pg_try_advisory_lock, que NÃO bloqueia. Quem perde recebe false e o Rails levanta ConcurrentMigrationError; como o entrypoint roda com `bash -e`, o db:prepare que falha derruba o container. A réplica morre no boot em vez de subir depois da que migrou. Somado ao acoplamento que a issue já apontava — boot preso no tempo e no sucesso da migration —, é o argumento inteiro. O default continua ligado de propósito. Inverter deixaria o `docker run` documentado no README e o compose local subindo contra um banco vazio, que é um jeito pior de falhar do que o problema evitado. A etapa de release não precisou de comando novo: o entrypoint só prepara o banco quando o comando é `./bin/rails server`, então `docker compose run --rm web ./bin/rails db:prepare` já passa direto. Isso virou um passo do smoke test — sem ele seria um caminho documentado que nada exercita, a mesma lacuna que o smoke test veio fechar na #81. Verificado: a condição do entrypoint nas cinco combinações que importam (server com a variável vazia/true/false, db:prepare, bin/jobs), o docker compose config com e sem a variável, e os gates de sempre no container — RuboCop 110 arquivos sem ofensas, zeitwerk:check limpo, RSpec 394 exemplos e 0 falhas. O comportamento dentro do container quem verifica é o smoke test do CI, que é onde ele de fato roda. Closes #82 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fecha a #82.
bin/docker-entrypointrodadb:prepareantes do Puma toda vez que o container sobe. É o que fazdocker compose up --buildfuncionar de primeira, e continua sendo o default — mas passou a ser desligável comDB_PREPARE_ON_BOOT=false, que é o que um deploy de verdade deve fazer, rodando as migrations numa etapa de release antes de subir as réplicas.docker compose up,docker run, demo de uma réplicaDB_PREPARE_ON_BOOT=false+ migrations antes das réplicasA premissa da issue precisava de correção
Ela falava em "todas as réplicas tentam preparar o banco ao mesmo tempo", sugerindo risco de corrupção. O schema nunca esteve em risco: as migrations do Rails pegam um advisory lock no Postgres — verifiquei em
activerecord-8.1.3.1,Migrator#with_advisory_lock.O que acontece de verdade é pior de um jeito diferente. O lock é obtido com
pg_try_advisory_lock, que não bloqueia: quem perde recebefalsee o Rails levantaConcurrentMigrationError. Como o entrypoint roda combash -e, odb:prepareque falha derruba o container — a réplica morre no boot em vez de subir depois da que migrou.Somado ao acoplamento que a issue já apontava (boot preso no tempo e no sucesso da migration), esse é o argumento inteiro. Está escrito assim no entrypoint e no README, no lugar da versão imprecisa.
Duas decisões
O default continua ligado. Inverter deixaria o
docker rundocumentado no README e o compose local subindo contra um banco vazio — um jeito pior de falhar do que o problema evitado. Quem faz deploy de verdade liga o modo release explicitamente, e a documentação diz isso.A etapa de release não precisou de comando novo. O entrypoint só prepara o banco quando o comando é
./bin/rails server, entãodocker compose run --rm web ./bin/rails db:preparejá passa direto. Isso virou um passo do smoke test: sem ele, seria um caminho documentado que nada exercita — a mesma lacuna que o smoke test da #81 veio fechar para a imagem inteira.Verificação
servercom a variável vazia /true/false,db:prepare,bin/jobs) — só a primeira e a terceira preparam;docker compose configcom e sem a variável, resolvendo para""e"false";zeitwerk:checkAll is good!, RSpec 394 exemplos / 0 falhas.O que não verifiquei localmente: o comportamento dentro do container. Exigiria rebuildar a imagem (~10 min nesta máquina, com o Docker Desktop já tendo caído duas vezes hoje), e o passo novo do smoke test roda exatamente isso no CI — que, aliás, é onde as duas últimas diferenças Windows/Linux apareceram.