Módulo 11 · Engenharia de Software · Aula 12

Coleta e
Extração

Contrato da fonte, estratégias de captura e idempotência, com a construção de uma extração incremental sobre uma origem transacional que sofre atualização e exclusão.

Watermark CDC Idempotência Postgres · DuckDB

Computação 1 · Prof. Hermano Peixoto · 09/09/2026

OrigemBanco, API, arquivo, evento
contrato
ExtraçãoJanela, watermark, retry
estratégia
Controlebatch_id, rejeitados, replay
auditoria
BronzeFidelidade à origem
destino

Continuidade · da Aula 10 para a Aula 12

O lakehouse está de pé, e agora o dado precisa chegar até ele

A Aula 10 decidiu onde e como o dado fica guardado. Esta aula trata de como ele entra, com que garantias e sob qual possibilidade de reprocessamento.

Aulas 2-4Modelagem dimensional
Aulas 8-9Governança de dados
Aula 10Armazenamento
Aula 12Coleta e extração
Aula 13Transformação e carga
A extração é a única etapa do pipeline que depende de um sistema sobre o qual a equipe de dados não tem autoridade. Toda garantia ausente na origem se converte em regra de engenharia no destino.

Roteiro · 120 minutos · uma hora de exposição, uma hora de prática

A primeira hora estabelece o critério, e a segunda constrói a extração em sala

A segunda hora é atividade em grupo: extrair de uma origem transacional que sofre atualização e exclusão, e medir o que cada estratégia perde.

1ª hora · Bloco 01
20 min

Contrato da fonte

A fronteira da extração, o perfil da origem e a semântica de atualização.

1ª hora · Bloco 02
25 min

Estratégias

Full load, incremental por watermark, CDC e idempotência.

1ª hora · Bloco 03
15 min

APIs, arquivos e operação

Paginação, retry, chegada atômica, controle e replay.

2ª hora · Atividade
60 min

Card de trabalho

Extração incremental sobre Postgres, com mutações que a quebram.

Objetivo: escolher a estratégia de extração pela semântica de atualização da origem, e provar a escolha medindo o que cada uma captura e o que deixa passar.

Bloco 1 · A fronteira

A extração é o ponto em que o dado deixa de ser de outro time

Antes dessa fronteira, o dado obedece às regras de quem o produz. Depois dela, a responsabilidade pela completude e pela rastreabilidade é do pipeline.

origemSistema transacionalOtimizado para escrita e para o negócio, sem compromisso com a análise
→
extraçãoJanela e watermarkDecide o que ler, quando ler e o que fazer quando a leitura falha
→
destinoBronzeFidelidade à origem, com carimbo de ingestão e identificador de lote
Assimetria

A origem não foi projetada para ser lida

O sistema transacional otimiza a escrita e o atendimento ao usuário. A leitura analítica compete por recurso, e a origem pode limitar, atrasar ou recusar a extração sem aviso. A janela de disponibilidade integra o contrato.

Consequência

A completude precisa ser verificada, não presumida

A extração que termina sem erro pode ter trazido metade dos registros. A verificação se faz por contagem reconciliada com a origem, e não pelo encerramento do processo.

Tratar o encerramento sem exceção como prova de completude. O processo termina normalmente quando a origem devolve página vazia por limite de requisições.

Bloco 1 · Perfil da fonte

O levantamento da origem antecede a primeira linha de código

Nove atributos determinam a estratégia de extração. Levantá-los depois da implementação custa a reescrita do pipeline.

1

Responsável pela origem e canal de comunicação em caso de mudança.

2

Chave natural que identifica o registro de forma estável ao longo do tempo.

3

Semântica de atualização: a origem corrige a linha, ou insere uma nova?

4

Exclusão física ou lógica, e como ela é observável de fora.

5

Timezone dos carimbos de tempo e se há horário de verão na série.

6

Janela de disponibilidade: quando a origem aceita carga de leitura.

7

Limites de requisição, de volume por página e de tempo de conexão.

8

Campos sensíveis, classificados antes da primeira extração.

9

Volume e crescimento, que determinam se o full load continua viável.

Assumir a existência de um campo de atualização confiável. Muitas origens alteram a linha por rotina administrativa sem tocar nesse campo, e a alteração nunca chega ao destino.

Bloco 1 · Semântica de atualização

O comportamento da origem diante da correção define o que é possível capturar

Três comportamentos distintos, com consequências opostas para a estratégia de extração.

Somente inserção

A origem nunca altera o passado

Cada fato gera uma linha nova, e a correção entra como novo registro. É o caso mais simples: o incremental por carimbo de tempo captura tudo.

Estratégia: incremental por timestamp de criação.

Atualização no lugar

A origem corrige a própria linha

O registro muda de estado sem mudar de identidade. A captura depende de um campo de atualização que a origem mantenha de forma disciplinada em toda escrita.

Estratégia: incremental por timestamp de atualização, com verificação periódica.

Exclusão física

A origem remove a linha

O registro desaparece sem deixar rastro consultável. Nenhuma consulta ao estado atual revela o que existia antes, porque não há o que ler.

Estratégia: captura pelo log de transações, ou reconciliação periódica de chaves.

Pergunta de projeto: na origem do parceiro de vocês, o cancelamento de um pedido produz uma linha nova, altera a linha existente ou a remove? A resposta determina qual das três estratégias é admissível, e as três não são intercambiáveis.

Bloco 1 · Tipos de origem

Cada tipo de origem impõe um contrato e um modo de falha

O que se negocia com quem mantém a origem, e como a extração degrada quando o contrato não é cumprido.

OrigemO que precisa ser negociadoModo de falha característicoDefesa correspondente
Banco relacionalRéplica de leitura, janela e acesso ao logA consulta analítica concorre com a transação e é interrompidaExtrair da réplica, em janela acordada e com lote limitado
APILimite de requisições, paginação e contagem declaradaPágina vazia devolvida por limite, interpretada como fimValidar pela contagem declarada e aplicar retry com backoff
ArquivoConvenção de nome, checksum e sinal de conclusãoLeitura do arquivo enquanto ele ainda está sendo gravadoSeparar landing de processamento e mover após o checksum
EventoSchema registrado, retenção e garantia de entregaReentrega do mesmo evento após falha parcialIngestão idempotente por chave natural e janela
O contrato da fonte é documento de projeto, e não conhecimento tácito de quem escreveu a primeira versão da extração.

Bloco 2 · Estratégias de extração

A estratégia se escolhe pela semântica da origem, e não pelo volume

O volume determina o custo, e a semântica de atualização determina a corretude. A segunda restringe a primeira.

Full load

custo alto · corretude alta

Como funciona
Lê a origem inteira a cada execução e substitui o destino por completo.
Captura
Inserção, atualização e exclusão, sem exigir campo de controle.
Limite
O custo cresce com o acervo, e a janela de origem pode não comportá-lo.
Use quando
O volume permite, ou como reconciliação periódica de outra estratégia.

Incremental por carimbo

custo baixo · corretude condicional

Como funciona
Lê o que mudou desde a última marca de tempo processada com sucesso.
Captura
Inserção e atualização, desde que a origem mantenha o campo com disciplina.
Limite
A exclusão física nunca chega, e o destino diverge de forma permanente.
Use quando
A origem só insere, ou mantém o campo de atualização de forma verificada.

Captura pelo log

custo médio · corretude alta

Como funciona
Lê o log de transações da origem e recebe cada operação como evento.
Captura
Inserção, atualização e exclusão, com a ordem em que ocorreram.
Limite
Exige retenção do log na origem, acesso privilegiado e garantia de ordenação.
Use quando
Exclusões e correções retroativas alteram a resposta analítica.
Regra de decisão: a origem que apaga registros exclui o incremental por carimbo de tempo como estratégia única. A alternativa admissível é a captura pelo log, ou a reconciliação periódica por full load.

Bloco 2 · Watermark

A marca d'água registra até onde a extração chegou com sucesso

É um valor persistido, avançado apenas quando o lote inteiro conclui. A janela seguinte parte dele, com sobreposição deliberada.

09:00lote anterior
10:00lote anterior
11:00sobreposição
12:00lote atual
13:00evento atrasado
—excluído na origem
capturado pela janela chega depois da marca e exige sobreposição jamais capturado por esta estratégia
Sobreposição

A janela seguinte recobre o fim da anterior

O evento gravado na origem no instante da virada da janela pode não estar visível quando a extração lê. A sobreposição de alguns minutos recupera esse registro, e a deduplicação por chave natural remove a repetição resultante.

Avanço condicionado

A marca avança apenas com o lote concluído

Avançar a marca antes de a gravação concluir cria uma lacuna permanente: a janela seguinte parte de um ponto cujo conteúdo nunca foi persistido, e nenhuma execução posterior o alcança.

Avançar a marca d'água no início do lote. Uma falha no meio da gravação produz perda silenciosa, porque a janela seguinte já parte do ponto seguinte.

Bloco 2 · Divergência

O incremental por carimbo diverge de três formas distintas

As três produzem destino incorreto sem emitir erro, e é isso que as torna difíceis de detectar em produção.

Evento na origemO que a extração observaEfeito no destinoCorreção
Exclusão físicaA linha desaparece, sem alteração de carimboO registro permanece no destino indefinidamenteCaptura pelo log, ou reconciliação de chaves por anti-junção
Atualização sem carimboNada, porque o campo de controle não se moveuO destino guarda o valor anterior como se fosse o vigenteGatilho na origem, ou reconciliação periódica por full load
Escrita retroativaUm registro com carimbo anterior à marca d'águaO registro nunca entra, porque a janela já passou daquele pontoSeparar data do evento da data de ingestão e filtrar pela segunda
A divergência é cumulativa. Cada execução acrescenta registros ao desvio, e nenhuma execução posterior o corrige por conta própria.
A defesa mínima é a reconciliação: comparar periodicamente a contagem e a soma de uma medida entre origem e destino, e declarar a tolerância aceita.

Bloco 2 · Captura pelo log

O log de transações registra a operação, e não apenas o estado final

O banco já grava cada escrita em um log para garantir durabilidade e recuperação. A captura de mudanças lê esse mesmo log.

-- o que a consulta ao estado atual devolve SELECT * FROM pedido WHERE id = 4711; -- (nenhuma linha: foi excluído) -- o que o log de transações preservou {op: "c", id: 4711, status: "criado", lsn: 88123} {op: "u", id: 4711, status: "pago", lsn: 88470} {op: "d", id: 4711, anterior: {...}, lsn: 88902}
Consequência analítica: a exclusão passa a ser um fato datado e auditável. O destino registra que o pedido existiu, quanto tempo permaneceu e quando deixou de existir.
✓

Confirme a retenção do log na origem: ela define a janela máxima de replay.

✓

Garanta ordenação por chave: as operações do mesmo registro precisam chegar em ordem.

✓

Trate o consumo como ao menos uma vez e torne a aplicação idempotente.

✓

Planeje a carga inicial: o log cobre o presente, e o passado exige um instantâneo.

✓

Negocie o acesso privilegiado: a leitura do log exige permissão que o DBA controla.

✓

Monitore o atraso de consumo: log não consumido é log que expira e vira lacuna.

Iniciar a captura pelo log sem a carga inicial correspondente. O destino passa a conter apenas os registros alterados a partir daquele instante, e o acervo anterior permanece ausente.

Bloco 2 · Idempotência

A mesma janela reprocessada produz o mesmo destino

É a propriedade que torna o replay seguro, e sem ela nenhuma falha parcial pode ser corrigida por repetição.

-- carga idempotente por chave natural MERGE INTO bronze.pedido d USING ( SELECT * FROM extraido QUALIFY row_number() OVER ( PARTITION BY order_id ORDER BY atualizado_em DESC) = 1 ) o ON d.order_id = o.order_id WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT ...;
Três elementos

Chave natural, ordenação e desempate

A chave identifica o registro, a ordenação decide qual versão prevalece e a regra de desempate resolve o empate de forma determinística. Sem os três declarados, duas execuções da mesma janela produzem resultados distintos.

Auditoria

batch_id e marca d'água persistidos

Cada execução recebe um identificador, e o registro guarda de qual lote veio. O reprocessamento se torna uma operação declarada, com efeito conhecido antes de ser executada.

Confiar em exclusão seguida de inserção fora de transação. A falha entre as duas operações deixa o destino vazio, e a consulta executada nesse intervalo devolve resultado incorreto sem erro.

Bloco 3 · APIs

A resposta bem-sucedida não constitui prova de completude

O código de status informa que a requisição foi atendida, e nada declara sobre quantos registros deveriam ter vindo.

Paginação

O fim se declara, não se deduz

Encerre a paginação pela contagem total declarada ou pelo cursor de continuação, e não pela primeira página vazia. O limite de requisições devolve página vazia com status de sucesso.

Limite e retry

Recuo exponencial com teto

A repetição imediata agrava a sobrecarga que causou a recusa. O intervalo entre tentativas cresce a cada falha, com variação aleatória para evitar que todos os consumidores repitam no mesmo instante.

Resposta original

Persistir antes de interpretar

Grave a resposta como veio, antes de qualquer conversão. Quando o formato mudar ou a interpretação se revelar errada, o reprocessamento parte do original em vez de exigir nova extração.

Checkpoint: persista o cursor a cada página concluída. A extração interrompida na página 400 de 900 retoma do ponto de parada, e não do início.
Encerrar a paginação no primeiro retorno vazio. O limite de requisições produz exatamente esse retorno, e a extração termina incompleta relatando sucesso.

Bloco 3 · Arquivos

O arquivo precisa estar completo antes de ser considerado disponível

A chegada de um arquivo é um processo com duração, e a leitura durante esse intervalo produz carga parcial que se apresenta como bem-sucedida.

✓

Separe landing de processamento, e mova o arquivo apenas após verificar o checksum.

✓

Exija sinal de conclusão: arquivo auxiliar ou renomeação atômica ao terminar a gravação.

✓

Valide encoding, delimitador e schema antes de processar, e rejeite com motivo registrado.

✓

Detecte reenvio pelo checksum: o mesmo arquivo entregue duas vezes não deve duplicar o destino.

✓

Trate coluna nova como evento de governança, com decisão registrada e não como falha.

Schema drift

A origem muda o arquivo sem avisar

Uma coluna acrescentada, renomeada ou reordenada altera a interpretação de todo o arquivo. A extração posicional quebra em silêncio: o valor de uma coluna passa a ser lido como se fosse de outra, e a carga conclui sem erro.

Defesa: leitura por nome de coluna, validação do schema contra o contrato registrado e alerta quando a diferença aparece.

Ler o arquivo enquanto ele ainda está sendo gravado. A carga sai parcial, o processo relata sucesso e a diferença só aparece na conferência de fechamento.

Bloco 3 · Operação

O registro de execução é o que torna o reprocessamento possível

A tabela de controle transforma a extração em operação auditável, com estado consultável e replay previsível.

-- tabela de controle da extração CREATE TABLE ctl.extracao ( batch_id UUID, -- identifica a execução origem VARCHAR, -- qual fonte janela_inicio TIMESTAMP, -- de onde leu janela_fim TIMESTAMP, -- até onde leu watermark TIMESTAMP, -- marca avançada ao concluir linhas_lidas BIGINT, bytes BIGINT, rejeitadas BIGINT, destino_rejeitos VARCHAR, status VARCHAR, -- concluido | falha | parcial iniciado_em TIMESTAMP, concluido_em TIMESTAMP, erro VARCHAR );
O registro rejeitado permanece acessível com o dado original e o motivo. Sem ele não há como reprocessar nem como explicar a diferença ao time de negócio.
O procedimento de replay precisa ser documentado e executado ao menos uma vez fora de incidente. Procedimento nunca testado não é procedimento.

Segunda hora · Card de trabalho em sala

Três perguntas medidas sobre uma origem que muda em sala

Em grupo, sobre a origem montada em sala: extrair, sofrer mutações e medir o que cada estratégia deixou passar.

1

Quantas linhas o incremental deixou de capturar?

Compare o destino do incremental com o de um full load posterior às mutações. A diferença é um número a explicar.

2

Quantos excluídos permaneceram no destino?

Identifique por anti-junção as chaves do destino ausentes na origem, e declare o efeito sobre a receita.

3

Reprocessar a janela altera o destino?

Execute a mesma janela duas vezes e compare a contagem. A carga é idempotente quando os dois números coincidem.

10minOrigem no ar e carregada
10minFull load de referência
15minIncremental por marca
15minMutações e divergência
10minReplay e conclusão

Segunda hora · Arquitetura

O Postgres como origem transacional e o DuckDB como extrator

O lakehouse da Aula 10 permanece como destino. O que se acrescenta é uma origem viva, que sofre inserção, atualização e exclusão durante o encontro.

origemPostgres · lojaTabela de pedidos com carimbo de atualização, sujeita a mutação em sala
→
extraçãoDuckDB · postgresAnexa a origem, aplica a janela e grava o lote com batch_id
→
destinoMinIO · bronzeParquet no bucket lakehouse, com carimbo de ingestão
Justificativa do Postgres

A origem precisa poder mudar durante a aula

O arquivo CSV é imutável e não permite observar o que acontece quando a origem corrige e apaga registros. O banco transacional torna a divergência reproduzível em sala, com número medido em vez de descrição.

Continuidade

O destino é o mesmo da Aula 10

O bucket, a convenção de prefixo e o formato Parquet permanecem. A aula acrescenta ao lakehouse a camada de controle e o carimbo de lote, sem refazer o ambiente.

Segunda hora · Preparação · 10 minutos

A origem transacional no ar e carregada com os pedidos

Um container e um bloco de configuração. O MinIO da Aula 10 permanece como está.

# 1. origem transacional docker run -d --name origem -p 5432:5432 \ -e POSTGRES_PASSWORD=olist \ -e POSTGRES_DB=loja postgres:16 # 2. MinIO da Aula 10 continua no ar docker start minio # 3. motor duckdb lakehouse.duckdb
-- 4. anexar a origem e criar a tabela INSTALL postgres; LOAD postgres; ATTACH 'host=localhost port=5432 dbname=loja user=postgres password=olist' AS origem (TYPE postgres); CREATE TABLE origem.pedido AS SELECT order_id, customer_id, order_status, CAST(order_purchase_timestamp AS TIMESTAMP) AS comprado_em, CAST(order_purchase_timestamp AS TIMESTAMP) AS atualizado_em FROM read_csv_auto('olist/olist_orders_dataset.csv'); CREATE SCHEMA IF NOT EXISTS ctl;
Verificação de partida: SELECT count(*) FROM origem.pedido deve devolver 99 441. Este número é a referência de todas as comparações do encontro, e precisa ser anotado antes de qualquer extração.

Segunda hora · Full load · 10 minutos

A extração completa estabelece a referência de comparação

Executada uma vez, antes de qualquer mutação, ela define o estado correto contra o qual as estratégias seguintes serão medidas.

-- full load: lê a origem inteira e grava a bronze com carimbo de lote SET VARIABLE lote = uuid(); COPY ( SELECT *, getvariable('lote') AS batch_id, now() AS ingerido_em FROM origem.pedido ) TO 's3://lakehouse/bronze/pedido_full' (FORMAT parquet, OVERWRITE_OR_IGNORE, COMPRESSION zstd); -- registra a execução na tabela de controle INSERT INTO ctl.extracao SELECT getvariable('lote'), 'postgres.pedido', NULL, now(), max(atualizado_em), count(*), 0, 0, NULL, 'concluido', now(), now(), NULL FROM origem.pedido;
Anote: a contagem gravada, o tempo de execução e o tamanho do prefixo no bucket. Os três reaparecem na comparação final.
A marca d'água nasce aqui, como o maior valor de atualizado_em observado. Toda janela incremental parte deste ponto.

Segunda hora · Incremental · 15 minutos

A extração incremental lê apenas o que mudou desde a última marca

Cada grupo implementa a janela, a sobreposição e o avanço condicionado da marca d'água.

-- 1. lê a marca d'água da última execução concluída SET VARIABLE marca = (SELECT max(watermark) FROM ctl.extracao WHERE status = 'concluido'); -- 2. janela com sobreposição deliberada de 5 minutos CREATE OR REPLACE TABLE stg.lote AS SELECT * FROM origem.pedido WHERE atualizado_em > getvariable('marca') - INTERVAL 5 MINUTE; -- 3. aplica de forma idempotente, deduplicando pela chave natural INSERT OR REPLACE INTO bronze.pedido SELECT * FROM stg.lote QUALIFY row_number() OVER (PARTITION BY order_id ORDER BY atualizado_em DESC) = 1; -- 4. só agora a marca avança, com o lote já persistido INSERT INTO ctl.extracao SELECT uuid(), 'postgres.pedido', getvariable('marca'), now(), max(atualizado_em), count(*), 0, 0, NULL, 'concluido', now(), now(), NULL FROM stg.lote;
Inverter a ordem dos passos 3 e 4. A marca avançada antes da gravação transforma qualquer falha em lacuna permanente, porque a janela seguinte já parte do ponto posterior.

Segunda hora · Mutações · 15 minutos

A origem muda de três maneiras, e o incremental observa apenas uma

Execute o bloco abaixo na origem, rode o incremental de novo e meça. Os três casos são deliberados e os números são conferíveis.

-- A. atualização disciplinada: move o carimbo (500 pedidos) UPDATE origem.pedido SET order_status = 'canceled', atualizado_em = now() WHERE order_id IN (SELECT order_id FROM origem.pedido LIMIT 500); -- B. atualização sem disciplina: NÃO move o carimbo (300 pedidos) UPDATE origem.pedido SET order_status = 'unavailable' WHERE order_id IN (SELECT order_id FROM origem.pedido LIMIT 300 OFFSET 1000); -- C. exclusão física: a linha deixa de existir (200 pedidos) DELETE FROM origem.pedido WHERE order_id IN (SELECT order_id FROM origem.pedido LIMIT 200 OFFSET 5000);
Caso A · 500

Capturado

O carimbo se moveu, a janela alcança as linhas e o destino recebe o novo estado.

Caso B · 300

Não observado

O carimbo permaneceu no valor anterior, e nada indica à extração que a linha mudou.

Caso C · 200

Jamais capturado

A linha não existe mais na origem, e nenhuma consulta ao estado atual pode revelá-la.

A medida do encontro: após o incremental, a origem tem 99 241 pedidos e o destino tem 99 441. A divergência de 500 registros — 300 com estado incorreto e 200 que deixaram de existir — é o resultado a explicar por escrito.

Segunda hora · Correção · 10 minutos

A reconciliação por chave revela o que a janela não alcança

Sem acesso ao log de transações, a defesa disponível é comparar periodicamente o conjunto de chaves da origem com o do destino.

-- 1. chaves que sumiram da origem: exclusões nunca capturadas SELECT count(*) AS excluidos_nao_propagados FROM bronze.pedido d ANTI JOIN origem.pedido o USING (order_id); -- 2. linhas cujo estado diverge: atualização sem carimbo SELECT count(*) AS estado_divergente FROM bronze.pedido d JOIN origem.pedido o USING (order_id) WHERE d.order_status <> o.order_status; -- 3. marcação lógica da exclusão no destino UPDATE bronze.pedido SET excluido_em = now() WHERE order_id NOT IN (SELECT order_id FROM origem.pedido);
Decisão a registrar

Exclusão marcada ou removida

Marcar a exclusão preserva o histórico e permite responder desde quando o pedido deixou de existir. Remover a linha alinha o destino ao estado atual e apaga a informação. A escolha é de negócio, e precisa estar declarada.

Custo

A reconciliação lê a origem inteira

A comparação de chaves tem custo próximo ao do full load. Por isso ela é periódica, e não a cada execução. A frequência se define pela tolerância a divergência declarada no requisito não funcional.

Espera-se 200 chaves ausentes na origem e 300 linhas com estado divergente. Os dois números precisam corresponder exatamente às mutações aplicadas.

Segunda hora · Replay

A mesma janela executada duas vezes produz a mesma contagem

A verificação encerra o laboratório e é a prova de que a extração pode ser reprocessada sem intervenção manual.

-- contagem antes do replay SELECT count(*) AS antes FROM bronze.pedido; -- reexecuta a MESMA janela, com o mesmo ponto de partida -- (repetir os passos 2 e 3 do slide do incremental) -- contagem depois: o número precisa ser idêntico SELECT count(*) AS depois FROM bronze.pedido; -- e a auditoria registra duas execuções distintas SELECT batch_id, janela_inicio, linhas_lidas, concluido_em FROM ctl.extracao ORDER BY concluido_em DESC LIMIT 2;
O critério de aceite: a contagem permanece igual e a tabela de controle registra dois lotes com identificadores distintos.
Se a contagem crescer, a chave de deduplicação está incorreta ou ausente. O crescimento é a assinatura da carga não idempotente.

Segunda hora · Conferência

Os valores de referência para conferir a extração

Números esperados em cada etapa, sobre a tabela de pedidos da Olist com as mutações do slide anterior aplicadas.

EtapaO que verificarReferência
Origem carregadaContagem na tabela do Postgres99 441 pedidos, idênticos ao CSV
Full loadContagem gravada na bronze99 441, com um único batch_id
Após as mutaçõesContagem na origem99 241, com 200 excluídos fisicamente
IncrementalLinhas trazidas pela janelaOrdem de 500, correspondentes ao caso A
ReconciliaçãoAnti-junção e comparação de estado200 chaves ausentes e 300 estados divergentes
ReplayContagem antes e depois da reexecuçãoIdêntica, com dois lotes na tabela de controle
Divergência nos números pode decorrer de outra ordem de aplicação das mutações. Exige-se que a sequência executada esteja registrada junto do resultado.

Segunda hora · Uso de IA · em paralelo

A IA escreve a extração, e o grupo responde pela reconciliação

O assistente acelera a escrita do SQL e do controle. A conferência dos números permanece atribuição do grupo e determina a correção do resultado.

Prompt 1 · Contrato

Levantar antes de extrair

"Este é o schema da tabela de pedidos. Liste as perguntas que preciso responder sobre a origem antes de escolher entre full load, incremental por carimbo e captura pelo log."

Prompt 2 · Geração

Escrever a janela e o controle

"Escreva SQL DuckDB que extraia do Postgres anexado apenas o que mudou desde a última marca d'água, com sobreposição de cinco minutos, aplicação idempotente e registro em tabela de controle."

Prompt 3 · Crítica

Procurar a perda silenciosa

"Aponte, neste pipeline, o que se perde quando a origem apaga uma linha, o que acontece se a execução falhar depois de gravar metade e o que quebra se a mesma janela rodar duas vezes."

✓

Confira a contagem em cada etapa e explique cada diferença antes de seguir.

✓

Verifique se o SQL gerado avança a marca d'água antes ou depois da gravação.

✓

Registre o prompt junto do SQL, uma vez que ele integra o registro da decisão.

Segunda hora · Medição

As evidências que cada grupo mede e registra

Cada linha é um número obtido por execução, e não uma afirmação sobre o comportamento esperado do pipeline.

EvidênciaComo obterO que ela demonstra
Custo de cada estratégiaTempo e linhas lidas do full load contra o incrementalQuanto a janela economiza em leitura da origem
Divergência acumuladaAnti-junção entre destino e origem após as mutaçõesQue a perda é silenciosa e cumulativa
Efeito no negócioSoma de receita no destino contra a soma na origemQue a divergência técnica altera o número apresentado
IdempotênciaContagem antes e depois do replay da mesma janelaQue a reentrega não duplica o dado
AuditoriaLinhas em ctl.extracao ao final do encontroQue cada execução é rastreável e reproduzível
A terceira linha é a que conecta o laboratório ao parceiro: uma diferença de 500 pedidos em 99 441 parece pequena até ser convertida em receita e apresentada como número de fechamento.

Ponte com a Aula 1 · Spec-Driven Development

Do tema à especificação executável

A decisão de extração entra no projeto como requisito, decisão registrada e critério verificável.

RF-005

Requisito funcional

Ingerir todas as alterações de pedidos da origem, inclusive exclusões e correções retroativas.

RNF-005

Requisito não funcional

Atraso da marca d'água menor ou igual a uma hora; taxa de rejeição até 0,1%; qualquer janela dos últimos 30 dias reprocessável sem intervenção manual.

ADR-ING-01

Decisão de arquitetura

Captura pelo log de transações em vez de incremental por campo de atualização. Contexto: a origem apaga registros e corrige lançamentos com data retroativa. Consequência: exige retenção do log e garantia de ordenação.

Cenário de aceite

Critério verificável

Dado que o lote de 09/09/2026 já foi carregado, quando reprocesso o mesmo identificador de lote, então o volume no destino permanece igual e a auditoria registra duas execuções.

A escolha entre incremental e captura pelo log é decisão de arquitetura com consequência de custo e de acesso. Registrá-la evita que a próxima equipe a refaça sem conhecer o motivo.

Entrega do card de trabalho

A extração versionada, os três números e a decisão registrada

O que o grupo entrega ao final da segunda hora, e o que será conferido.

Artefato

Pipeline de extração e o relato da divergência

O SQL da carga inicial, da janela incremental e da reconciliação; os três números medidos; e uma frase por número que declare o efeito sobre a decisão de negócio do parceiro.

1

A origem transacional está no ar e a contagem inicial coincide com a do CSV.

2

A tabela de controle registra cada execução com lote, janela, marca d'água e status.

3

A marca d'água avança somente após a gravação do lote concluir.

4

Os três casos de mutação foram aplicados e a divergência resultante está medida.

5

O replay da mesma janela mantém a contagem e registra duas execuções distintas.

6

A decisão sobre exclusão marcada ou removida está declarada por escrito.

Aula 12 · Síntese

A estratégia de extração determina quais mudanças o destino é capaz de observar, e a reconciliação determina em quanto tempo a divergência é descoberta.

Debezium — Change Data Capture Google SRE — Handling overload RFC 9110 — HTTP Semantics DuckDB — Postgres extension
Pergunta final: na origem do parceiro, quantos dias a divergência levaria para ser percebida sem reconciliação?

Sobre este encontro

Coleta e Extração · 09/09/2026 · Prof. Hermano

Objetivo de aprendizagem

Levantar o contrato de uma fonte, escolher entre full load, incremental por carimbo de tempo e captura pelo log a partir da semântica de atualização da origem, e construir uma extração idempotente cuja divergência seja medida e explicada.

Estratégia do encontro

Primeira hora de exposição dialogada em três blocos, cada um encerrado por checklist de aplicação e erro comum. Segunda hora de atividade em grupo: os estudantes montam uma origem transacional em Postgres com os pedidos da Olist, extraem por full load e por janela incremental para o lakehouse da Aula 10, aplicam mutações deliberadas de atualização e exclusão na origem e medem exatamente o que cada estratégia deixou de capturar.

Estrutura do encontro

  1. 1ª hora · Bloco 1 (20 min) — Contrato da fonte: a fronteira da extração, o perfil da origem, a semântica de atualização e os quatro tipos de origem com seus modos de falha.
  2. 1ª hora · Bloco 2 (25 min) — Estratégias: full load, incremental por marca d'água e captura pelo log, as três formas de divergência do incremental e a idempotência como condição do replay.
  3. 1ª hora · Bloco 3 (15 min) — APIs, arquivos e operação: paginação, recuo exponencial, chegada atômica, schema drift, tabela de controle e procedimento de replay.
  4. 2ª hora · Card de trabalho (60 min) — Em grupo: origem no ar e carregada (10 min), full load de referência (10 min), incremental por marca d'água (15 min), mutações e medição da divergência (15 min), reconciliação, replay e conclusão escrita (10 min).