137 lines
7.8 KiB
Markdown
137 lines
7.8 KiB
Markdown
# 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](21-checklist-validacao.md) 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](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:
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
node --import=tsx scripts/rollback-local-probe.ts seed
|
|
```
|
|
|
|
Troca só de web e worker, volumes intactos:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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/ready` voltou `ready`.
|
|
- 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 ficou `healthy`.
|
|
|
|
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
|
|
|
|
1. Anote a imagem que está no ar. No ensaio, o retorno é `adaptador-planilhas:bd0ecab`.
|
|
2. Pare só `web` e `worker` do projeto isolado, com `stop -t 30`.
|
|
3. Aponte `ADAPTER_IMAGE` para a tag do commit desejado.
|
|
4. Suba de novo com `up -d --no-deps --force-recreate web worker`.
|
|
5. Não rode migration de down. Se `migrations` não ficar `ok`, 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.
|
|
6. 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.
|