A maioria dos times descobre que precisava de point-in-time recovery depois que o banco já foi pro chão.
O Cloudflare D1 tem uma feature chamada Time Travel. Ela permite restaurar qualquer banco de dados para qualquer minuto dentro dos últimos 30 dias. Funciona via replay do Write-Ahead Log: o D1 mantém um stream de todas as alterações e reconstrói o estado do banco até o ponto exato que você precisa.
O detalhe que me chamou atenção: vem ativado por padrão. Não precisa configurar, não precisa habilitar, não precisa lembrar de criar snapshot antes de rodar aquele migration arriscado na sexta às 18h. Está sempre gravando.
E não custa nada extra. Sem taxa por restore, sem cobrança por retenção de histórico. O D1 cobra por reads, writes e storage. Só. Sem database hours, sem egress, sem surpresa na fatura.
Compara com o cenário de quem usa RDS na AWS: point-in-time recovery precisa ser habilitado, consome storage adicional, e o restore cria uma instância nova que você precisa redirecionar manualmente. Funciona, mas é um processo que no meio de uma crise ninguém quer estar fazendo pela primeira vez.
Outro ponto: se você restaurar pro estado de 10 minutos atrás e perceber que era pra ter ido mais longe, pode restaurar de novo pra um ponto anterior. Restaurar não apaga os bookmarks mais antigos.
É claro que D1 é um banco SQLite no edge, não um Postgres com replicação multi-região. Tem limites de tamanho, não suporta todos os cenários. Mas pra aplicações que rodam no ecossistema Cloudflare Workers, ter PITR gratuito e automático é o tipo de coisa que você só valoriza quando precisa.
Plano gratuito: 7 dias de retenção. Plano pago: 30 dias.
Alguém ainda escolhe o minuto do corte
Time Travel grava o WAL e permite voltar a qualquer minuto da janela. O produto não escolhe o minuto. Em incidente, a pergunta continua humana: qual foi o último estado conhecido como bom? Foi o DELETE sem WHERE das 14:12, a migration das 18:03, ou o job que correu às 18:40 em cima do estrago?
Sem esse recorte, restaurar "um pouco antes" pode reaplicar o erro ou jogar fora writes legítimos. Bookmark é lexicograficamente ordenável e derivável de timestamp Unix; isso ajuda a ser preciso. Não substitui o rastro de deploy, o log da migration e um canal onde alguém diga "parem de escrever".
Preserve evidência antes do restore. Dump, export, ou pelo menos o bookmark atual que o wrangler d1 time-travel info devolve. Se o restore der errado, você vai querer o ponto de agora e o ponto anterior. A operação devolve um bookmark para desfazer. Anote. Incidentes em que ninguém copiou o ID viram adivinhação.
O ganho automático é histórico existir mesmo quando o time esqueceu o snapshot de sexta. O custo que permanece é decisão, comunicação e validação. PITR barato sem runbook é só um botão perigoso a mais no CLI.
Restore no lugar cancela o que está no ar
A documentação é direta: restaurar para um ponto no tempo sobrescreve o banco no lugar. Queries em voo são canceladas. Não há fork para uma cópia nova, pelo menos neste desenho. "Restaurar em outra base e redirecionar tráfego" é o hábito de quem veio de RDS. No D1 atual, o hábito precisa mudar: o restore é destrutivo no identificador que a aplicação já usa.
Por isso o ensaio importa. Rode o comando em base de staging, veja o tempo, veja o que a aplicação faz quando as queries voltam erro, veja como o Worker se comporta com conexão recusada no meio do request. Em produção, o mesmo gesto atinge o usuário na hora.
Há teto de 10 restores a cada 10 minutos por banco. Retry ansioso no meio do incidente encontra limite. O undo usa o bookmark anterior devolvido pelo próprio restore. Se você restaurou demais para o passado, ainda pode ir a um ponto entre os dois, porque bookmarks antigos não somem. O que some é o estado que estava no ar, a menos que alguém o tenha exportado.
Export para R2 via Workflows existe para quem precisa de retenção além da janela. Isso é backup de arquivo, não PITR. Distinguir os dois no runbook evita a reunião em que alguém pede "o banco de 45 dias atrás" e descobre que a janela era 30.
Retenção de sete ou trinta dias muda o runbook
Workers Free guarda 7 dias. Paid, 30. A feature está sempre ligada; a janela não é. Um bug silencioso que só aparece no dia 12, em conta free, já saiu da história. Times que usam D1 em preview no plano free precisam saber que o ensaio de restore de uma migration da semana passada pode ser impossível.
O runbook, então, cita a janela do ambiente. Produção paga: 30 dias, ainda assim finito. Staging free: 7. Dados que a auditoria pede por um ano não cabem no Time Travel. Cabem em export, em outro banco, ou em não usar D1 como sistema de registro eterno.
Cobrança não ganha linha extra por restore nem por retenção de histórico. Continua rows read, rows written e storage. Restore em si não é o item da fatura que assusta. Storage do banco, sim, se o WAL e os dados crescerem. O ponto operacional é outro: como o restore é in-place, o risco é perda de writes recentes, não a nota fiscal.
Marque no calendário de incidentes o dia em que a janela vence para o evento. Se a migration ruim foi no dia 1 e hoje é dia 28 no plano pago, a folga é pequena. PITR "sempre on" anestesia o time até a janela fechar.
Ensaio de restore fora do incidente
A comparação com RDS no texto de abertura vale pelo ritual, não pela paridade de produto. Em crise, ninguém quer descobrir a flag do Wrangler, a versão do storage (production versus alpha legado, que ainda usa snapshot) e o fato de que o comando pede confirmação y/N enquanto o Slack explode.
Uma vez por trimestre, em staging: anote um bookmark, faça uma escrita conhecida, restaure para o bookmark, confira se a escrita sumiu, desfaça para o bookmark posterior, confira se voltou. Meça o tempo. Grave o output. Coloque o comando no runbook com o nome real do banco, não com YOUR_DATABASE.
Confirme que o banco está no subsystem de produção (wrangler d1 info, campo version). Alpha legado não tem Time Travel. Descobrir isso no incidente é o tipo de detalhe que transforma PITR teórico em "a gente não tinha".
Wrangler 3.4.0 ou superior é requisito documentado. Imagem de CI e laptop do on-call precisam dessa versão. Sem pin, o comando some do path na hora errada.
Teto de SQLite no edge continua valendo
PITR não aumenta o tamanho máximo do banco, não transforma D1 em Postgres com réplica multi-região, não muda o fato de cada database ser single-threaded. 10 GB no plano pago, 500 MB no free, query de até 30 s, restore com limite de taxa. Time Travel resolve um classe de erro (escreveu errado, quer voltar). Não resolve modelo de dados que já passou do teto, nem hot shard, nem relatório analítico.
Se a aplicação já está no limite de tamanho, o WAL histórico não é o problema principal. Se a aplicação precisa de clone para blue/green, o produto ainda não oferece fork. O workaround é export/import, com o custo e a janela que isso tem. Planejar a migração perigosa em horário em que o restore in-place é aceitável continua sendo trabalho de operação.
Para quem já está em Workers, a conta fecha assim: histórico de minutos sem taxa extra, restore destrutivo, janela curta, ensaio obrigatório. Isso é barato em dinheiro e caro em disciplina. O time que só celebra "é grátis e vem ligado" vai usar o comando pela primeira vez com o banco errado.


