
Sessenta contêineres em um servidor
Uma caixa bare-metal executa dezenas a centenas de contêineres Hoody. KSM e BTRFS dedup fazem o custo marginal próximo a zero.
Provisione uma entrada gerenciada de cron no dia em que a limpeza começa. Defina expires_at alguns dias após a última execução prevista. O script vai fatiando o trabalho noite após noite e então faz DELETE em si mesmo quando não sobra nada. Sem lembrete no calendário, sem crontab zumbi, sem revisão anual de limpa-os-limpadores.
# tail of cleanup-stale-uploads.sh removed=$(find /uploads -mtime +90 -delete -print | wc -l) echo "$removed files removed" # self-aware tail: nothing left → retire if [ -z "$(ls /uploads)" ]; then curl -fsS -X DELETE \ "$CRON_URL/entries/$ENTRY_ID" fi
A cauda autoconsciente. A entrada de cron é a última linha do próprio script.
Dia 1 limpou 247 arquivos obsoletos. Dia 7 limpou nenhum — e disparou DELETE na própria entrada.
# tail of cleanup-stale-uploads.sh removed=$(find /uploads -mtime +90 -delete -print | wc -l) echo "$removed files removed" # self-aware tail: nothing left → retire if [ -z "$(ls /uploads)" ]; then curl -fsS -X DELETE \ "$CRON_URL/entries/$ENTRY_ID" fi
A cauda autoconsciente. A entrada de cron é a última linha do próprio script.
Três fases discretas. Cada transição é mecânica, nenhuma exige que um humano se lembre. A entrada sabe quando seu trabalho terminou e quando seu slot no calendário acabou.
Agendamento @daily, comando aponta para um script slicer, expires_at é definido um pouco após a última execução prevista. O prazo está na entrada — não num doc do Notion, não numa thread do Slack.
Cada execução deleta uma fatia de dados obsoletos para que o banco não seja martelado. Dia 1 pode limpar 247 arquivos; dia 6, só 1. O ritmo é limitado pelo que de fato resta.
O último bloco do script verifica se o alvo está vazio. Se sim, dispara DELETE /entries/[self]. Se de alguma forma não disparar, expires_at aciona a rede de segurança alguns dias depois.
Dois gatilhos independentes — a verificação do próprio script e o expires_at da API — convergem para o mesmo resultado: uma linha de crontab que não sobrevive ao seu propósito.
O Hoody Cron é um wrapper JSON-CRUD em torno do crontab do sistema. POST cria a entrada; DELETE remove; expires_at é a rede de segurança. O script que roda à noite é o que sabe quando terminou — então é ele quem chama o DELETE.
# day 0 — provision the cleanup curl -X POST \ https://cron.containers.hoody.com/users/me/entries \ -H "Content-Type: application/json" \ -d '["schedule":"@daily","command":"/srv/jobs/cleanup-stale-uploads.sh","expires_at":"2026-05-05T00:00:00Z"]' # response HTTP/1.1 201 Created { "id":"f3a1", "expires_at":"2026-05-05T00:00:00Z", "enabled":true }
# inside the cron command itself if [ -z "$(ls /uploads)" ]; then curl -X DELETE \ "$CRON_URL/entries/$ENTRY_ID" fi # response HTTP/1.1 204 No Content # entry f3a1 was here. f3a1 deleted itself.
$ENTRY_ID é o UUID retornado pelo POST — o script pode lê-lo de um arquivo passado pela linha de comando da entrada, ou de $HOODY_ENTRY_ID em runtime. De qualquer forma, a entrada de cron deleta a entrada de cron.
Não é a deleção que importa. É que ninguém precisa lembrar que nada disso existe daqui a três meses.
@daily roda a cada 24 horas. O script deleta uma fatia de dados obsoletos — alguns milhares de arquivos, alguns milhares de linhas — e encerra. O banco fica calmo; a curva de carga parece que nada aconteceu.
expires_at está na entrada como JSON. Quando dispara, a linha é removida do crontab do sistema. Daqui a três engenheiros ninguém vai estar passando por 200 linhas se perguntando o que cleanup-stale-uploads-v3 ainda faz.
O script faz DELETE em si mesmo na noite em que o trabalho acaba. Se um bug pula esse caminho, expires_at aposenta a entrada alguns dias depois. Dois mecanismos independentes; um deles vai disparar.
Cada entrada gerenciada é uma linha de JSON que a API injeta no crontab do sistema. A escala é limitada pelo que o próprio cron suporta, não pelo Hoody.
@daily é o ritmo canônico de limpeza. Se você precisa de passagens mais frequentes, pode usar expressões de 5 campos até * * * * * — resolução por minuto.
Um timestamp ISO-8601 na entrada. Quando passa, a API remove a linha na próxima varredura. A limpeza nunca demora além do próprio prazo.
DELETE /users/[user]/entries/[id] de dentro do comando em execução funciona porque o daemon do cron não trava o próprio crontab — a API aplica a mudança com segurança.
Expressões padrão de cron de 5 campos mais macros (@hourly, @daily, @weekly, @monthly, @yearly). Isolamento por usuário; cada usuário do sistema tem seu próprio crontab. A página de Cron do Hoody Kit documenta tanto entradas gerenciadas quanto acesso bruto ao crontab, caso você precise do formato antigo.
A limpeza roda toda noite até que aquilo que está sendo limpo tenha sumido.
Onde quer que uma tarefa de limpeza deva sumir sozinha — esses são os padrões que ela substitui:
Provisione a limpeza. Defina sua data de aposentadoria. Vá embora.