O documento foi apagado e voltou depois da recuperação da fila

Uma integração remove um documento da base consultada pelo agente. Horas depois, um consumidor retoma uma mensagem antiga de atualização. Como o registro não existe mais, o adaptador faz um upsert e recria o conteúdo.

Encaixe vazio ligado a dois moldes translúcidos; uma mão retira um molde e um batente vermelho bloqueia uma peça antiga.
Ilustração conceitual. Exclusão deve alcançar cópias e impedir reintrodução por históricos, preservando apenas marcador mínimo e evidência necessária.

A exclusão havia funcionado. O sistema perdeu a informação necessária para distinguir um objeto nunca visto de um objeto removido.

Um tombstone é um marcador de remoção. Ele preserva evidência mínima de que determinada identidade foi excluída, sem precisar guardar o conteúdo apagado. Numa projeção versionada, essa barreira permite recusar uma atualização anterior à exclusão.

O recorte deste guia é a preservação da exclusão diante de atraso, replay e reconstrução. A sincronização incremental mantém a projeção entre rodadas. A retenção de dados define finalidades e prazos. Aqui, a decisão é quando uma entrada pode voltar a criar um objeto e quando o marcador pode ser descartado com segurança.

Exclusão precisa ter identidade e autoridade

Antes de aplicar uma remoção, o adaptador deve confirmar sistema produtor, cliente, objeto, tipo de evento e autorização. Um pedido em texto livre ou o desaparecimento numa listagem parcial não constitui prova suficiente.

O marcador pode conter:

cliente: T1
objeto: D7
geracao: 1
versao_exclusao: 8
origem: repositorio autorizado
evento: identificador da remoção
estado: REMOVIDO
confirmacao_por_destino: registro de progresso
revisao_retencao: definida pela política aplicável

Não copie o documento para o marcador. Evite nome, e-mail, texto e outros campos que não sustentem o controle. Mesmo um identificador pode continuar sendo dado pessoal ou informação restrita; a empresa precisa avaliar finalidade, acesso e prazo com os responsáveis.

Use o contrato de dados para definir a semântica. Campo ausente, campo nulo e evento de exclusão podem ter significados diferentes. Um null só representa remoção quando o protocolo escolhido o define assim.

Aplique a barreira no mesmo compromisso da mudança

Uma projeção pode manter conteúdo e estado de exclusão no mesmo registro. Outra pode usar um registro separado de barreiras. Nos dois desenhos, a decisão de aceitar a atualização deve ser atômica com a alteração local que ela permite.

Procedimento para uma origem que emite versão crescente por objeto e geração:

  1. validar identidade, escopo e contrato do evento;
  2. obter a versão já aceita, inclusive se o objeto estiver removido;
  3. recusar versões anteriores;
  4. tratar versão igual como repetição somente se a identidade do evento e seu significado forem compatíveis;
  5. aplicar uma versão posterior conforme a regra do ciclo de vida;
  6. confirmar o novo estado antes de avançar o processamento.

Uma consulta ao tombstone seguida de escrita incondicional deixa uma corrida entre as operações. O armazenamento precisa aplicar condição de versão ou transação apropriada. O controle de concorrência detalha essa fronteira.

Se a origem não fornece sequência comparável, não invente uma a partir do relógio do worker. Pode ser necessário consultar a autoridade, usar a posição documentada do feed ou suspender o objeto até reconciliação. A política depende do recurso.

Defina se uma identidade removida pode nascer novamente

Uma versão maior não deve autorizar, por si só, qualquer recriação. Existem ciclos diferentes:

  • exclusão terminal: a mesma identidade permanece encerrada;
  • restauração autorizada: um evento específico reabre o objeto;
  • nova geração: o identificador externo é reutilizado, mas representa outra existência;
  • exclusão limitada a uma coleção: o objeto pode continuar válido em outra fonte.

No desenho por geração, a chave inclui cliente, objeto e geração. Atualização antiga da geração 1 não altera a geração 2. A criação da nova geração precisa vir de um evento autorizado e de uma política conhecida; o modelo não pode decidir que se trata de um cadastro novo porque o texto mudou.

O guia de ordenação de mensagens trata versões atrasadas em objetos ainda presentes. O tombstone mantém essa proteção quando o conteúdo já saiu da projeção.

Kafka oferece um contrato específico de tombstone

A documentação do Apache Kafka 4.1 descreve, em logs compactados, um registro com chave e payload nulo como marcador de exclusão. A compactação remove registros anteriores daquela chave. O próprio marcador também pode ser removido depois de um período.

O documento alerta que um consumidor pode perder marcadores se seu atraso ultrapassar a janela de delete.retention.ms. Portanto, uma cópia local antiga não se torna correta apenas porque o consumidor voltou a percorrer o que ainda existe no log.

Isso não significa que todo sistema precise de Kafka. Também não significa que o broker aplica a política de exclusão do CRM ou apaga vetores externos. Cada consumidor precisa interpretar o contrato e confirmar seu próprio destino.

Antes de implementar, confira a versão instalada, a política do tópico e as configurações efetivas. O exemplo deste artigo não executa Kafka nem mede o tempo de compactação.

Retenção deve considerar quem ainda pode reaplicar o passado

Definir um TTL isolado para o marcador cria uma segunda falha: o sistema apaga a barreira enquanto uma fila, backup ou consumidor antigo ainda pode entregar conteúdo anterior.

A avaliação deve incluir a janela de replay permitida, a indisponibilidade tolerada dos consumidores, a retenção de filas e arquivos, os backups restauráveis e o tempo necessário para confirmar destinos derivados.

Quando não houver um limite demonstrável, escolha uma estratégia explícita. Por exemplo: proibir retomada incremental depois de certo atraso e exigir reconstrução integral de uma fonte autoritativa. Na reconstrução, substituir a projeção antiga por uma geração completa evita conservar linhas que já não possuem evento recuperável de remoção.

O consumer lag ajuda a encontrar consumidores fora da janela segura. Não reduza a retenção apenas porque todos estão saudáveis agora; considere a recuperação que a empresa promete suportar.

Ficha de exclusão que sobrevive ao conteúdo removido

EXEMPLO SINTÉTICO — ficha de conferência de tombstone
Chave: cliente T1 / objeto D7 / geração 1.
[ ] Aceitar conteúdo v7 somente sob evento válido.
[ ] Ao aceitar exclusão v8, remover payload e persistir REMOVIDO + versão 8 no mesmo compromisso atômico. O marcador não copia o documento.
[ ] Reentrega de atualização v7: recusar; não recriar conteúdo.
[ ] Repetição da exclusão v8: manter estado somente se identidade e significado forem compatíveis; conflito exige tratamento.
[ ] Nova geração 2 / v1: exigir criação autorizada e manter chave separada. Atualização da geração 1 não altera a geração 2.
[ ] T2 / D7 / geração 1: preservar isolamento de cliente.
Contraprova: apagar toda a entrada e aceitar upsert v7 permite recriação indevida.
Antes de descartar a barreira: verificar replay, backups, consumidores atrasados e confirmação dos derivados; se não há janela segura demonstrada, definir reconstrução pela autoridade. Esta ficha não comprova execução.
Representação explicativa original da fixture sintética T1/D7 descrita no laboratório histórico do artigo. Não é captura nem nova execução; a checagem local relatada não valida Kafka ou exclusão distribuída.

Laboratório local: exclusão, reentrega e nova geração

Em 22 de outubro de 2026, na preparação editorial original, foi executado um laboratório local em Python e SQLite, com dados sintéticos. A tabela usou chave por cliente, objeto e geração e atualização condicional que só aceitava versão maior.

A sequência foi:

T1 / D7 / geração 1: conteúdo aceito na versão 7
T1 / D7 / geração 1: exclusão aceita na versão 8
T1 / D7 / geração 1: atualização antiga na versão 7 recusada
T1 / D7 / geração 1: repetição da exclusão mantém o estado
T1 / D7 / geração 2: criação sintética autorizada na versão 1
T2 / D7 / geração 1: objeto de outro cliente preservado

A versão 8 da geração removida permaneceu com payload nulo. Fechar e reabrir o banco manteve essa barreira. A nova geração e o outro cliente conservaram seus registros separados.

Um controle ingênuo em memória, que apagava toda a entrada e aceitava o próximo upsert, recriou D7 ao receber a versão 7. Esse contraste verifica o motivo da barreira.

O laboratório valida persistência local após reabertura e a comparação de versões desse exercício. Não testa queda de energia, concorrência entre processos, compactação Kafka ou exclusão distribuída. A fixture também pressupõe eventos válidos; um adaptador de produção precisa detectar versões iguais com payload conflitante, validar a autorização de recriação e aplicar a política terminal.

Confirme a exclusão em cada derivado

Banco local, cache e índice de busca podem concluir em momentos diferentes. Registre o progresso por destino, bloqueie a recuperação quando a política exigir e trate falha de limpeza como pendência com dono.

A limpeza de documentos órfãos no Azure AI Search resolve um destino específico. O tombstone complementa esse trabalho: impede que uma atualização atrasada volte a alimentar o índice depois da remoção.

Antes de encerrar a implementação, teste reentrega antiga, exclusão duplicada, identidade reutilizada, cliente diferente, consumidor atrasado além da retenção e restauração de cópia anterior à exclusão. Verifique conteúdo recuperável, estado do marcador e confirmação por destino. Contar mensagens processadas não prova que o dado deixou de circular.

Fonte oficial verificada em 22 de outubro de 2026

O contrato por geração, a política de recriação e o laboratório são propostas de arquitetura da publicação original. Para começar, identifique uma exclusão real do processo e procure todos os caminhos que ainda podem reaplicar uma versão anterior. A liberação depende de provar que esses caminhos respeitam a barreira ou exigem reconstrução segura.