Soixante conteneurs sur un seul serveur
Une seule machine bare-metal fait tourner des dizaines à des centaines de conteneurs Hoody. La déduplication KSM et BTRFS rend le coût marginal quasi nul.
Provisionnez une entrée cron managée le jour où le nettoyage commence. Mettez expires_at quelques jours après le dernier run attendu. Le script tranche le travail nuit après nuit, puis se DELETE quand il ne reste plus rien. Pas de rappel calendrier, pas de crontab zombie, pas de revue annuelle pour nettoyer les nettoyages.
# 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 queue auto-consciente. L'entrée cron est la dernière ligne de son propre script.
Jour 1 a vidé 247 fichiers obsolètes. Jour 7 n'a rien vidé — et a tiré DELETE sur sa propre entrée.
# 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 queue auto-consciente. L'entrée cron est la dernière ligne de son propre script.
Trois phases discrètes. Chaque transition est mécanique, aucune n'exige qu'un humain s'en souvienne. L'entrée sait quand son travail est fait et quand son créneau calendrier est passé.
Schedule @daily, command pointe vers un script slicer, expires_at est positionné juste après le dernier run attendu. La deadline est dans l'entrée — pas dans un doc Notion, pas dans un thread Slack.
Chaque run supprime une tranche de données obsolètes pour ne pas marteler la base. Jour 1 peut vider 247 fichiers ; jour 6 juste 1. Le rythme est borné par ce qui reste réellement.
Le dernier bloc du script vérifie si la cible est vide. Si oui, il tire DELETE /entries/[self]. Si pour une raison quelconque ça ne se fait pas, expires_at déclenche le filet de sécurité un ou deux jours plus tard.
Deux déclencheurs indépendants — la propre vérification du script et l'expires_at de l'API — convergent vers le même résultat : une ligne de crontab qui ne survit pas à son propos.
Hoody Cron est un wrapper JSON-CRUD autour du crontab système. POST crée l'entrée ; DELETE la retire ; expires_at est le filet de sécurité. Le script qui tourne nuit après nuit est celui qui sait quand c'est fini — donc c'est celui qui appelle 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 est l'UUID retourné par le POST. Passe-le par la ligne de commande pour que le script puisse le lire depuis un fichier ou argv. De toute façon, l'entrée cron supprime l'entrée cron.
Ce n'est pas la suppression qui compte. C'est que personne n'aura à se souvenir que tout ça existe dans trois mois.
@daily tourne toutes les 24 heures. Le script supprime une tranche de données obsolètes — quelques milliers de fichiers, quelques milliers de lignes — et sort. La base reste calme ; la courbe de charge a l'air de rien.
expires_at est dans l'entrée en JSON. Quand il se déclenche, la ligne est retirée du crontab système. Trois ingénieurs plus tard, personne ne fouille 200 lignes pour deviner ce que cleanup-stale-uploads-v3 fait encore.
Le script se DELETE la nuit où le travail est fait. Si un bug saute ce chemin, expires_at retire l'entrée un ou deux jours plus tard. Deux mécanismes indépendants ; l'un des deux se déclenchera.
Chaque entrée managée est une ligne de JSON que l'API injecte dans le crontab système. Le scaling est borné par ce que cron lui-même peut tenir, pas par Hoody.
@daily est le rythme canonique du nettoyage. Si vous avez besoin de passages plus fréquents vous pouvez utiliser des expressions à 5 champs jusqu'à * * * * * — résolution à la minute.
Un timestamp ISO-8601 sur l'entrée. Quand il passe, l'API retire la ligne au prochain balayage. Le nettoyage ne traîne jamais au-delà de sa propre deadline.
DELETE /users/[user]/entries/[id] depuis l'intérieur de la commande en cours fonctionne parce que le daemon cron ne verrouille pas son propre crontab — l'API balaie le changement en sécurité.
Expressions cron standard à 5 champs plus macros (@hourly, @daily, @weekly, @monthly, @yearly). Isolation par utilisateur ; chaque utilisateur système a son propre crontab. La page Cron du Hoody Kit documente à la fois les entrées managées et l'accès crontab brut si vous avez besoin de la forme historique.
Le nettoyage tourne nuit après nuit jusqu'à ce que la chose à nettoyer ait disparu.
Partout où une tâche de nettoyage est censée disparaître toute seule — voici les patterns que ça remplace :
Provisionne le nettoyage. Fixe sa date de retraite. Pars.