
Sesenta contenedores en un servidor
Un servidor bare-metal ejecuta decenas a cientos de contenedores Hoody. KSM y dedup BTRFS hacen que el costo marginal sea casi cero.
Incluye `.hoody/crontab` en el repo junto a tus jobs. Cuando el script de despliegue arranca un contenedor para `main`, `feature/billing-v2` o cualquier rama de preview, hace PUT de ese archivo a la API de Cron del nuevo contenedor. La programación viaja con la rama — y desaparece cuando la rama desaparece.
un archivo por rama · misma ruta en cada repo · sin servidor cron compartido
Cada contenedor de rama ejecuta Hoody Cron. El script de despliegue lee el crontab incluido y lo envía con PUT al endpoint raw-crontab del nuevo contenedor. El contenedor ejecuta la programación que describe el archivo — nada más, nada menos.
#!/bin/sh
# Aprovisiona un contenedor nuevo para esta rama.
BRANCH=$(git branch --show-current)
CTR=$(hoody containers create --from main-snapshot)
# Reemplaza el crontab del contenedor por el del repo.
curl -X PUT --data-binary @.hoody/crontab \
-H "Content-Type: text/plain" \
https://$CTR-cron-1.hoody.com/users/root/crontab
# Listo. La programación de la rama vive en su contenedor.
echo "deployed $BRANCH → $CTR"# Endpoint raw-crontab de Hoody Cron — reemplaza el archivo entero de forma atómica.
PUT /users/root/crontab HTTP/1.1
Host: ctr_4d72b9-cron-1.hoody.com
Content-Type: text/plain
0 2 * * * /srv/jobs/billing-rollup-v2.sh
*/15 * * * * /srv/jobs/sync-stripe.py
@hourly curl -fsS http://localhost/healthz
*/5 * * * * /srv/jobs/diff-v1-v2.sh
HTTP/1.1 200 OK
# 200 OK: el daemon de cron se recarga, la programación queda activa en menos de un segundo.El crontab son datos que la rama transporta, no estado que el servidor cron recuerde. Borra el contenedor y no queda ninguna entrada que limpiar — el archivo se fue con el disco.
Cuando la programación es un archivo en el repo, desaparecen tres categorías de trabajo.
Cuando cambias `billing-rollup.sh` a v2, la nueva programación llega en el mismo pull request. Quien revisa ve la línea cron justo al lado del script. Revierte un commit y la programación se revierte con él.
Los contenedores de rama son efímeros. Cuando haces merge o cierras la rama, desmontas el contenedor. El crontab vivía dentro, así que la programación desaparece sin que nadie limpie — no hay servidor cron compartido sosteniendo entradas obsoletas.
Un job experimental por hora en `experiment/llm-rollups` corre en su propio contenedor con su propio sistema de archivos. El daemon cron de staging nunca lo ve; el de producción tampoco. No hay guardas `if BRANCH_ENV` dentro de los propios jobs.
El modelo estándar de "un crontab gestionado por ops" y el modelo ligado a la rama fallan en direcciones opuestas. Mismo job, radio de impacto muy distinto.
La diferencia no es una funcionalidad — es dónde vive la programación. Un archivo que la rama transporta, frente a una fila de una tabla compartida que la rama toma prestada.
Cron por contenedor es una superficie REST real — tres familias de endpoints, sintaxis cron estándar, aislamiento total por usuario. Cifras de la spec de la API de Cron, no benchmarks inventados.
Cada contenedor de rama tiene su propio crontab por usuario. Haz PUT del archivo entero, GET para recuperarlo, reemplázalo de forma atómica. Sin tabla de programación compartida por detrás.
Crontab raw (GET/PUT), entradas gestionadas (POST/PATCH/DELETE con UUIDs y `expires_at`), y listado por usuario. Elige la que tu script de despliegue necesite.
El estándar `min hora día mes dow` más macros: `@hourly`, `@daily`, `@weekly`, `@monthly`, `@yearly`. La misma sintaxis que ya usa tu `.hoody/crontab`.
Según la API de Hoody Cron: GET/PUT /users/[user]/crontab y POST/PATCH/DELETE /users/[user]/entries en la URL del servicio cron de cada contenedor.
La programación vive junto al código que la ejecuta, en el mismo contenedor, en la misma rama.
Seis sitios donde solía vivir la programación cron, ninguno junto al código. El crontab ligado a la rama los hace todos redundantes.
Deja de sincronizar programaciones entre sistemas. Incluye el crontab en el repo. Deja que la rama lo transporte.