← System Design: decidir, dimensionar e recuperar sistemas
11 / 12 · 70 MIN

Materializar exportações recuperáveis

Separa a recolha consistente dos dados da produção do ficheiro e define o estado que autoriza a sua entrega.

Definir o resultado antes do worker

O laboratório cria source_rows, jobs e export_rows num cluster PostgreSQL temporário. A primeira tabela representa dados fictícios que podem mudar; a terceira conserva os valores escolhidos para uma exportação. Não basta guardar apenas ids e voltar a consultar a fonte durante a produção do ficheiro, porque isso pode misturar valores de momentos diferentes. O contrato pedagógico associa job_id a pares de id e units. Define também o significado de building, ready, running e complete. Esses nomes só são úteis quando ligados a condições verificáveis. Aqui ready significa que a materialização foi confirmada, enquanto complete inclui uma referência a um candidato selecionado e ao seu hash.

Não expor materialização parcial

Uma sessão começa uma transação, cria um job building e copia duas linhas. Antes do COMMIT, a segunda sessão não vê esse job. O guião executa depois ROLLBACK e confirma que desapareceram tanto o job como as linhas parciais. A observação demonstra a fronteira dessa transação local. Não houve processo morto, falha de energia ou recuperação de uma base danificada. Numa implementação real, a criação do job e a materialização podem ter outras fronteiras; se forem separadas, a equipa precisa de uma política para jobs incompletos. Uma mensagem de conclusão enviada cedo não seria corrigida automaticamente pelo rollback posterior.

Conservar valores numa única visão

O segundo percurso usa REPEATABLE READ. A primeira cópia guarda ids 1 e 2. Outra sessão altera units de id 3 para 999 e acrescenta id 4. A cópia seguinte, dentro da mesma transação, ainda guarda id 3 com 300 e não inclui id 4. O job passa a ready antes do COMMIT. Depois, outra sessão consegue observar três linhas materializadas, embora a fonte já tenha quatro e valores diferentes. A tabela de exportação permite produzir o ficheiro sem manter a transação de origem aberta durante toda a entrega. Contudo, o guião não impõe permissões de imutabilidade nessa tabela; qualquer garantia operacional de retenção e proteção precisa de configuração e testes próprios.

Distinguir candidato de resultado aceite

O coordenador escreve dois ficheiros locais, um por geração do job, com nomes distintos e abertura exclusiva. Ambos contêm a mesma representação JSON dos valores materializados. Antes de atualizar jobs, a coluna artifact continua vazia: ter bytes no disco não significa que um resultado tenha sido aceite. Esta ordem permite observar um candidato órfão sem alterar a decisão de conclusão. O guião não implementa uma transação distribuída entre a base e o filesystem. Também não executa upload para object storage nem entrega HTTP. A aplicação real precisa de definir quando disponibiliza a referência ao consumidor e como trata um ficheiro escrito sem publicação confirmada.

Verificar a referência e os bytes

Depois de publicar a geração atual, o consumidor pedagógico lê estado, geração, nome e digest da base e calcula SHA 256 sobre os bytes. Uma alteração controlada do ficheiro faz essa comparação falhar, embora jobs continue complete. O guião restaura apenas o seu próprio fixture para continuar os testes; isso não é uma recomendação de reparar um artefacto real a partir de dados não confiáveis. Um hash registado permite comparar conteúdo com uma referência esperada, mas não identifica por si só um produtor autorizado. A proteção do manifesto, dos ficheiros e das permissões continua necessária. O laboratório não contém assinatura digital ou armazenamento imutável.

Preparar recuperação e retenção

A limpeza pedagógica consulta as referências complete e apaga apenas o candidato não referenciado, sem concorrência. O ficheiro aceite fica preservado. Num grupo posterior, o guião remove deliberadamente esse ficheiro e confirma que o estado da base não muda: complete não garante disponibilidade futura. Um runbook deve distinguir ausência, divergência de hash, materialização incompleta e candidato órfão. Para cada situação, define diagnóstico, possibilidade de reconstrução, autorização e efeito sobre o consumidor. Retenção e recolha de ficheiros órfãos precisam de considerar trabalho ainda em curso. O presente guião não testa garbage collection concorrente, uma indisponibilidade real de storage ou restauro após perda de energia.

python3 content/labs/design-export/run.py --postgres-prefix /path/to/postgresql-18.6 --output /tmp/dr-export-new.json
# Use a fresh output path; owned cluster and files are temporary.
NA PRÁTICA

Uma exportação conserva três linhas com valores 100, 200 e 300, apesar de a fonte mudar o terceiro valor para 999 e ganhar outra linha.

Armadilhas comuns

Ficheiro existente como publicação, copiar páginas em visões diferentes, concluir apenas pelo estado da base e confundir rollback com recuperação após crash.

Tópicos relacionados: Paginação e snapshots · Transações locais

Leva esta ideia contigo

A exportação tem dados, estado e artefacto. A recuperação precisa de relacionar os três e de explicitar as fronteiras que não são atómicas.

Criar conta

Referência: Transaction isolation · System design patterns; PostgreSQL18 scoped examples; primary guidance consulted 2026-09-30