7.8 KiB
Ensaio local de rollback de imagem
Ensaio descartável feito em 17 de outubro de 2026, nesta máquina, no projeto Docker adaptador-rollback-ensaio. Não é o rollback da homologação nem o da produção da Elo Pro.
O gate F11 do checklist continua pendente. Ele exige duas imagens publicadas e o ambiente hml-ada.elopro.app. O procedimento de lá está na seção 10 de 20-homologacao-runbook.md. Este documento não o aprova.
O que foi comparado
| Atual | Anterior | |
|---|---|---|
| Commit | bd0ecabf41330d8e48dbe070cb090b25fd6eb64c |
2be97ea9694eb3fe44e125fbd2ab3e13d8cc488a |
| Tag da imagem | adaptador-planilhas:bd0ecab |
adaptador-planilhas:2be97ea |
| Id da imagem | sha256:bc06e875c96b2a1f28b406fd0512e40b37399550355f204d32d77ae766db9eed |
sha256:edc36b8532b172ea940ed6dd252e2f965a91694366adb5828e87f7c72dc520d9 |
git diff 2be97ea bd0ecab -- src migrations Dockerfile docker docker-compose.yml não tem diferença. O commit atual só acrescenta o smoke local, o package.json, o tsconfig.json e a documentação. As quatro migrations (0001 a 0004) são as mesmas. Por isso a imagem anterior convive com o schema aplicado pela imagem atual. Não houve downgrade de migration.
A tag adaptador-planilhas:local do compose principal não foi reescrita. Antes e depois do ensaio ela continuou sha256:1efe0dfab0a80518563bd8ac2905466eca5692c05a26818a397551fffc05f1fa, com web, worker, Postgres e Redis principais saudáveis. O banco adaptador seguiu com 1 modelo e as flags spreadsheet_adapter Alpha ligada e Beta desligada. O comando flag não foi executado.
Isolamento
Arquivo: docker-compose.rollback-local.yml.
| Recurso | Nome | Publicado no host |
|---|---|---|
| Projeto | adaptador-rollback-ensaio |
não |
| Rede | adaptador-rollback-ensaio |
não |
| Volume Postgres | adaptador-rollback-ensaio-postgres |
não |
| Volume storage | adaptador-rollback-ensaio-storage |
não |
| Banco | adaptador_rollback |
não |
| Redis | interno | não |
| Web | 127.0.0.1:3310 |
só loopback |
Não há build: nesse compose. Sem ADAPTER_IMAGE ele recusa subir, para não cair na tag :local. Postgres e Redis não têm porta no host. A sonda scripts/rollback-local-probe.ts só aceita http://127.0.0.1:3310.
Os volumes adaptador-planilhas-local-postgres e adaptador-planilhas-local-storage não entraram no ensaio. Não houve docker compose down -v no projeto principal, nem git reset.
Comandos executados
Conferência de compatibilidade, sem trocar de branch:
git diff --stat 2be97ea bd0ecab -- src migrations Dockerfile docker docker-compose.yml
git worktree add --detach "$TEMP/adaptador-2be97ea-src" 2be97ea
Imagens, sem mover a tag :local:
docker build -t adaptador-planilhas:bd0ecab --build-arg SENTRY_RELEASE=bd0ecabf41330d8e48dbe070cb090b25fd6eb64c --target runner .
docker build -t adaptador-planilhas:2be97ea --build-arg SENTRY_RELEASE=2be97eaf --target runner "$TEMP/adaptador-2be97ea-src"
Subida do ensaio e migration única, com a imagem atual:
export ADAPTER_IMAGE=adaptador-planilhas:bd0ecab
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml up -d postgres redis storage-init
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml run --rm --no-deps web migrate
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml up -d web worker
A migration só rodou depois do Postgres saudável. Aplicou 0001_platform_shim.sql, 0002_spreadsheet_adapter.sql, 0003_rls.sql e 0004_audit_append_only.sql. Não existe passo de down. 0003 e 0004 continuam sem caminho de volta, como no runbook.
Jornada fictícia:
node --import=tsx scripts/rollback-local-probe.ts seed
Troca só de web e worker, volumes intactos:
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml stop -t 30 web worker
export ADAPTER_IMAGE=adaptador-planilhas:2be97ea
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml up -d --no-deps --force-recreate web worker
Volta para a imagem atual, do mesmo jeito, com ADAPTER_IMAGE=adaptador-planilhas:bd0ecab.
Depois das evidências, só o projeto do ensaio foi removido:
docker compose -p adaptador-rollback-ensaio -f docker-compose.rollback-local.yml down -v
git worktree remove --force "$TEMP/adaptador-2be97ea-src"
Antes do down -v, os nomes listados eram apenas adaptador-rollback-ensaio, adaptador-rollback-ensaio-postgres e adaptador-rollback-ensaio-storage. As imagens :bd0ecab e :2be97ea foram mantidas. A tag :local não.
Resultado
Prontidão da imagem atual, antes da troca: HTTP 200, status=ready, environment=development, e config, database, migrations, redis, storage e job_mode em ok.
Dados fictícios gravados:
| Campo | Valor |
|---|---|
| Modelo | 52add4ba-88b5-4611-b8d7-4ffe33273d3e |
| Operação | ee5fb92f-57ba-4414-a7ab-b9635e243aea |
| Fonte | eabec970-e86d-4b39-8c76-c2b5d10b4674 |
| SHA-256 do XLSX original | 74a4130f7712f94727c6bbf8708b9e77fd34e61c7504da8b84be309cbd6d9559 |
| SHA-256 do XLSX exportado | 89abbca277ea2569bf63ac5cffcd581181b5b6e97d22a285cf21786e175608dc |
| SHA-256 do CSV exportado | 199e83c30d6fbae7174a4ecd563d32e9ece19a677209e79e88bb56116a6b8977 |
O mesmo SHA-256 do original foi lido no volume pela imagem atual e, depois da troca, pela imagem 2be97ea. O content_sha256 no banco isolado coincidiu. schema_migrations permaneceu nas quatro migrations. As flags do banco isolado nasceram do login local de desenvolvimento (Alpha ligada, Beta desligada) e não mudaram na troca de imagem.
Na imagem anterior e de novo na atual:
GET /api/health/readyvoltouready.- O modelo foi encontrado pelo id e pelo nome.
- A operação permaneceu
completed. - Os bytes armazenados de XLSX e CSV repetiram o SHA-256.
- O PDF voltou HTTP 200. O SHA-256 do PDF não se repete: ele é gerado no download, não fica gravado. Isso ocorreu nas duas imagens, não é incompatibilidade de rollback.
- O worker da imagem anterior registrou
[worker] pronto. Depois da restauração, o healthcheck do worker ficouhealthy.
Tempo observado da troca, do stop até o ready, no ensaio local: cerca de 3 s na ida para 2be97ea e 2,8 s na volta para bd0ecab. Esse número não descreve pull de registry, Nginx nem a flag do piloto.
Nenhuma incompatibilidade de schema apareceu. O rollback não foi interrompido.
Como repetir a recuperação
- Anote a imagem que está no ar. No ensaio, o retorno é
adaptador-planilhas:bd0ecab. - Pare só
webeworkerdo projeto isolado, comstop -t 30. - Aponte
ADAPTER_IMAGEpara a tag do commit desejado. - Suba de novo com
up -d --no-deps --force-recreate web worker. - Não rode migration de down. Se
migrationsnão ficarok, ou se o processo não subir, interrompa e volte para a tag atual pelo mesmo caminho. Schema incompatível é operação planejada, com backup, não rollback às pressas. - Confira
/api/health/ready, o modelo, o SHA-256 do original no volume e o download do XLSX e do CSV.
Na homologação real o equivalente está no runbook: tag staging-<sha>, up -d --no-deps web worker, e a flag do módulo é outro passo, feito com flag, antes da troca e só religada depois da saúde. Este ensaio não fez isso e não deve ser copiado para o servidor compartilhado.
Limitações
- As duas imagens executam o mesmo código de aplicação. O ensaio prova a troca de imagem com volume e schema preservados. Não prova um rollback atravessando uma migration nova.
- Não usa Supabase, SSO, Sentry nem bucket da Elo Pro.
- A flag do piloto não foi ligada nem desligada.
- O PDF não serve como hash de integridade entre downloads.
- O tempo de 3 s é só o recreate local das duas imagens já presentes no Docker.