
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.
Poste uma entrada cron na segunda com expires_at apontando para sexta às 09:00. O job avisa seu telefone a cada 30 minutos por quatro dias e se apaga no momento em que o turno acaba. O próximo plantonista posta o dele. Sem agendamento PagerDuty, sem configuração de scheduler compartilhada, sem lembrete de calendário para desativar.
a entrada que paginava m.dossantos só existe enquanto m.dossantos está de plantão
Três pontos na semana. A existência da entrada cron acompanha o turno com precisão — sem sobreposição, sem lacuna, sem linha de crontab esquecida.
Um curl com schedule */30, comando apontando para hoody-notifications/push/me e expires_at = sexta 09:00:00Z. O servidor retorna o id e7d3.
A cada 30 minutos, por quatro dias, a entrada roda e pinga o hoody-notifications. Só o seu dispositivo. O canal do time fica em silêncio.
Às 09:00:00Z o serviço cron apaga e7d3. O tick das 09:30 não tem nada para disparar. O próximo plantonista já postou o dele.
Cada plantonista escreve um POST quando o turno começa. O campo expires_at é o protocolo de handoff inteiro — o serviço cron faz a limpeza, no segundo certo.
O protocolo inteiro de rotação são duas chamadas HTTP por semana. O plantonista posta na segunda, lista na sexta, vê que a entrada já sumiu. Não há arquivo de agendamento compartilhado para fazer merge.
# monday 09:00 — i'm on call until friday 09:00 curl -X POST \ https://oncall.containers.hoody.com/users/me/entries \ -H "Content-Type: application/json" \ -d '["schedule":"*/30 * * * *","command":"curl -fsS hoody-notifications/push/m.dossantos","comment":"on-call wk19","expires_at":"2026-05-08T09:00:00Z"]' # response HTTP/1.1 201 Created { "id":"e7d3", "expires_at":"2026-05-08T09:00:00Z", "enabled":true }
# friday 09:01 — the next on-call took over curl GET https://oncall.containers.hoody.com/users/me/entries HTTP/1.1 200 OK [ // my entry e7d3 is gone — it expired // at 09:00 sharp. j.okafor's new // entry took over at 09:00:30. ] # no slack thread, no calendar reminder
Nenhum serviço de scheduler compartilhado está envolvido. A entrada cron é da pessoa de engenharia; nada na configuração do próximo plantonista depende do anterior limpar a sua.
Uma entrada de plantão que controla o próprio tempo de vida elimina três classes de erros que configurações PagerDuty e lembretes de calendário não conseguem.
Como o comando da entrada aponta para o seu endpoint pessoal de notificação, os escalonamentos vão para o seu telefone durante o turno, e só durante ele. Sem spam acidental no canal do time às 3 da manhã.
Não existe escalation_policy.yaml que todo mundo mexe. Cada engenheiro é dono da sua entrada. Dois plantonistas em fusos diferentes não conseguem entrar em conflito editando o mesmo arquivo.
Quando der sexta 09:00, você não pergunta 'espera, ainda estou recebendo isso?'. A entrada já se foi. Verificar o handoff é um GET que retorna uma linha a menos.
Os números vêm da Hoody Cron API. Limites reais, não inventados.
A expiração automática roda contra o relógio do sistema. Um expires_at em 09:00:00Z apaga dentro do mesmo minuto em que o tick cron dispara — sem atraso de 5 minutos por causa de zelador.
Expressões cron padrão de 5 campos mais macros @hourly / @daily / @weekly. */30 * * * * é o que dispara a cada 30 minutos durante o seu turno.
Cada usuário do sistema tem o próprio crontab. A entrada do próximo plantonista vive no /users/[name]/entries dele — nunca encosta na sua.
Limites conforme a Hoody Cron API: entradas gerenciadas são CRUD JSON com UUIDs e expires_at; acesso ao crontab raw disponível por usuário; isolamento de crontab por usuário é nativo.
Quando o turno acaba, a entrada cron acaba também — automaticamente.
As ferramentas padrão de prateleira quando você quer rotação de plantão. Cada uma cobra um serviço, um repositório de config e um ritual de handoff. Uma entrada cron com expires_at cobra um POST.
Pare de desativar linhas de crontab na manhã de sexta. Defina expires_at na segunda e esqueça.