ADR-041
Backup por job da aplicação, e não por cron e shell no servidor
Os backups simplesmente não rodavam, e a tela mostrava a configuração salva como se estivesse tudo certo: a agenda vivia num cron que o deploy não recria. Tudo que depende de passo manual pós-provisionamento acaba não sendo feito.
Contexto
O backup nasceu como scripts de shell no servidor, disparados por cron configurado pelo script de provisionamento. Funcionava, enquanto ninguém reprovisionasse a máquina. O deploy pelo pipeline não executa o script de provisionamento, então a agenda se perdia a cada reconstrução do servidor e não era recriada. O resultado é o pior possível nessa área: os backups simplesmente não rodavam, e a tela mostrava a configuração salva como se estivesse tudo certo.
Critérios que pesaram
Em ordem de peso.
- O mecanismo tem de subir junto com a aplicação, sem etapa manual.
- A janela de execução precisa ser editável sem publicar versão.
- Fuso horário correto, sem depender do fuso do servidor.
- Falha de um tipo de backup não pode impedir os outros.
Opções consideradas
- Manter cron e shell, documentando o passo manual pós-provisionamento: é o estado que produziu a falha, e depende de alguém lembrar exatamente no momento em que ninguém está pensando em backup. Descartada.
- Fixar a agenda no cron da aplicação. Tiraria a dependência do servidor e amarraria a janela ao código: mudar o horário exigiria publicar versão. Descartada.
- Job da aplicação disparando a cada minuto, com a agenda em arquivo de configuração editável pela tela.
Decisão
O backup é um job do Quartz no worker, que dispara a cada minuto, lê a configuração salva pela tela e compara o dia da semana e o horário atual, convertidos para o fuso da operação pela aplicação e não pelo fuso do processo, com as agendas cadastradas. Cada tipo de dado tem agenda própria e pode ter várias, o que permite combinar regras distintas para dias úteis e fim de semana; os dias seguem numeração padrão, fáceis de validar e de exibir. São três tipos: dump do banco da aplicação e do banco do Keycloak, pacote das configurações do servidor, e exportação do realm pela API de administração do Keycloak, reaproveitando a mesma representação que a console dele importa. O job dispara só o tipo agendado para aquele minuto, em vez de rodar tudo. Falha de um tipo é registrada e os demais seguem tentando; a falha do banco do Keycloak vira aviso e não bloqueia o dump principal, mas o contrário não vale: sem o dump da aplicação não há backup. Há ainda um interruptor geral por variável de ambiente, e execução manual pela tela, que roda os três tipos em paralelo.
Consequências
As duas metades pesam igual.
Melhorou
O backup passou a existir de fato, sem etapa manual e sem depender de reprovisionamento. A janela ficou editável pela tela, e o fuso deixou de depender de como o servidor está configurado.
Piorou
Um job disparando a cada minuto o dia inteiro para, na maior parte das vezes, não fazer nada, o que é barato, e é ruído contínuo no log até a política de amortecimento de execução ociosa entrar. O pg_dump precisa existir dentro dos containers, o que amarra a imagem à versão do PostgreSQL. E parte da documentação antiga do projeto, escrita para a abordagem de shell, sobreviveu descrevendo um mecanismo que não existe mais, e precisou ser marcada explicitamente como material histórico.
Revisitando hoje
Ainda de pé em set/2026. A lição não é sobre backup, é sobre onde mora a automação: tudo que depende de um passo manual pós-provisionamento acabará não sendo feito, e a área em que isso é mais caro é justamente aquela em que a ausência não dá sintoma: ninguém percebe que não há backup até precisar de um.
Primeiro de três registros sobre o backup. É a trilha mais desconfortável do acervo: quando ela começa, os backups simplesmente não rodavam, e a tela mostrava a configuração salva como se estivesse tudo certo. Está publicada como foi escrita, incluindo o que piorou.