
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.
Provisiona una entrada de cron gestionada el día que empieza la limpieza. Pon expires_at unos días después de la última ejecución prevista. El script va cortando el trabajo cada noche, y luego hace DELETE de sí mismo cuando no queda nada. Sin recordatorio en el calendario, sin crontab zombi, sin revisión anual de limpia-las-limpiezas.
# 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
La cola autoconsciente. La entrada de cron es la última línea de su propio script.
Día 1 limpió 247 archivos rancios. Día 7 no limpió ninguno — y disparó DELETE sobre su propia 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
La cola autoconsciente. La entrada de cron es la última línea de su propio script.
Tres fases discretas. Cada transición es mecánica, ninguna requiere que un humano se acuerde. La entrada sabe cuándo termina su trabajo y cuándo se acaba su hueco en el calendario.
Horario @daily, command apunta a un script slicer, expires_at se pone justo después de la última ejecución prevista. La fecha límite está en la entrada — no en un Notion, no en un hilo de Slack.
Cada ejecución borra un trozo de datos rancios para que no se castigue la base de datos. El día 1 puede limpiar 247 archivos; el día 6, solo 1. El ritmo lo marca lo que queda de verdad.
El último bloque del script comprueba si el destino está vacío. Si lo está, dispara DELETE /entries/[self]. Si por alguna razón no, expires_at activa la red de seguridad un par de días después.
Dos triggers independientes — la propia comprobación del script y el expires_at de la API — convergen en el mismo resultado: una línea de crontab que no sobrevive a su propósito.
Hoody Cron es un wrapper JSON-CRUD sobre el crontab del sistema. POST crea la entrada; DELETE la borra; expires_at es la red de seguridad. El script que corre cada noche es el que sabe cuándo ha terminado — así que es el que llama a 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 es el UUID que devuelve el POST — el script puede leerlo de un archivo que pasó la línea command de la entrada, o de $HOODY_ENTRY_ID en runtime. De cualquier manera, la entrada de cron borra la entrada de cron.
No importa el borrado. Importa que nadie tenga que acordarse de que esto existe dentro de tres meses.
@daily corre cada 24 horas. El script borra un trozo de datos rancios — unos pocos miles de archivos, unos pocos miles de filas — y termina. La base de datos se mantiene tranquila; la curva de carga parece que no pasó nada.
expires_at está en la entrada como JSON. Cuando se dispara, la línea se quita del crontab del sistema. Tres ingenieros más adelante, nadie está paseándose por 200 líneas preguntándose qué hace todavía cleanup-stale-uploads-v3.
El script hace DELETE de sí mismo la noche que termina el trabajo. Si un bug se salta esa rama, expires_at retira la entrada un par de días después. Dos mecanismos independientes; uno de los dos disparará.
Cada entrada gestionada es una fila JSON que la API inyecta en el crontab del sistema. El escalado lo limita lo que el propio cron puede aguantar, no Hoody.
@daily es el ritmo canónico de limpieza. Si necesitas pasadas más frecuentes puedes usar expresiones de 5 campos hasta * * * * * — resolución de minuto.
Un timestamp ISO-8601 en la entrada. Cuando pasa, la API quita la línea en el siguiente barrido. La limpieza nunca se queda más allá de su propia fecha límite.
DELETE /users/[user]/entries/[id] desde dentro del comando en ejecución funciona porque el daemon de cron no bloquea su propio crontab — la API barre el cambio de forma segura.
Expresiones cron estándar de 5 campos más macros (@hourly, @daily, @weekly, @monthly, @yearly). Aislamiento por usuario; cada usuario del sistema tiene su propio crontab. La página Cron del Hoody Kit documenta tanto las entradas gestionadas como el acceso crudo al crontab si necesitas la forma antigua.
La limpieza corre cada noche hasta que lo que se está limpiando ya no está.
Allí donde una tarea de limpieza se supone que debe desaparecer sola — estos son los patrones que reemplaza:
Provisiona la limpieza. Ponle fecha de jubilación. Vete.