
Soixante conteneurs sur un seul serveur
Une machine bare-metal exécute des dizaines à des centaines de conteneurs Hoody. La dédupplication KSM et BTRFS rend le coût marginal quasi nul.
Provisionnez une entrée cron managée le jour où le nettoyage commence. Définissez expires_at quelques jours après la dernière exécution prévue. Le script tranche le travail nuit après nuit, puis envoie un DELETE sur lui-même quand il ne reste plus rien. Pas de rappel d'agenda, pas de crontab zombie, pas de revue annuelle « 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 effacé 247 fichiers obsolètes. Jour 7 n'en a effacé aucun — et a déclenché 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 distinctes. Chaque transition est mécanique, aucune ne demande à un humain de se souvenir. L'entrée sait quand son travail est fini et quand son créneau de calendrier est terminé.
Planification @daily, command pointe vers un script trancheur, expires_at est défini juste après la dernière exécution prévue. La date butoir est dans l'entrée — pas dans un document Notion, pas dans un fil Slack.
Chaque exécution supprime une tranche de données obsolètes pour ne pas marteler la base. Le jour 1 peut effacer 247 fichiers ; le jour 6, à peine 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 déclenche DELETE /entries/[self]. S'il échoue pour une raison quelconque, expires_at déclenche le filet de sécurité quelques 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 utilité.
Hoody Cron est un wrapper JSON-CRUD autour de la 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 — c'est donc lui 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 renvoyé par le POST — le script peut le lire dans un fichier transmis par la ligne de commande de l'entrée, ou via $HOODY_ENTRY_ID au runtime. Dans les deux cas, l'entrée cron supprime l'entrée cron.
Ce qui compte n'est pas la suppression. C'est que personne n'aura à se souvenir que tout cela 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 fait comme s'il ne s'était rien passé.
expires_at est dans l'entrée en JSON. Quand il se déclenche, la ligne est retirée de la crontab système. Trois ingénieurs plus tard, personne ne fouille 200 lignes en se demandant ce que cleanup-stale-uploads-v3 fait encore.
Le script s'envoie un DELETE la nuit où le travail est fini. Si un bug saute ce chemin, expires_at met l'entrée à la retraite quelques jours plus tard. Deux mécanismes indépendants ; l'un des deux se déclenchera.
Chaque entrée managée est une ligne JSON que l'API injecte dans la crontab système. La mise à l'échelle est limitée par ce que cron lui-même peut contenir, 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 s'attarde jamais au-delà de sa propre date butoir.
DELETE /users/[user]/entries/[id] depuis la commande en cours d'exécution fonctionne parce que le démon cron ne verrouille pas sa propre crontab — l'API balaie le changement en toute sécurité.
Expressions cron standard à 5 champs plus macros (@hourly, @daily, @weekly, @monthly, @yearly). Isolation par utilisateur ; chaque utilisateur système a sa propre crontab. La page Cron du Hoody Kit documente à la fois les entrées managées et l'accès brut à la crontab si vous avez besoin de l'ancienne forme.
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 schémas qu'elle remplace :
Provisionnez le nettoyage. Fixez sa date de retraite. Partez.