
ستون حاوية على خادم واحد
صندوق معادن عارية واحد يشغل عشرات إلى مئات حاويات Hoody. يجعل KSM و BTRFS dedup التكلفة الإضافية قريبة من الصفر.
وفّر مُدخل cron مُداراً يوم بدء التنظيف. اضبط expires_at على بضعة أيام بعد آخر تشغيل متوقّع. السكربت يقطع العمل ليلاً، ثم يُرسل DELETE لنفسه حين لا يبقى شيء. لا تذكير في التقويم، لا crontab زومبي، ولا مراجعة سنوية لتنظيف-المُنظِّفات.
# 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
الذيل الواعي لذاته. مُدخل cron هو السطر الأخير من سكربته الخاص.
اليوم الأول مسح 247 ملفاً قديماً. اليوم السابع لم يمسح شيئاً — وأطلق DELETE على مُدخله الخاص.
# 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
الذيل الواعي لذاته. مُدخل cron هو السطر الأخير من سكربته الخاص.
ثلاث مراحل منفصلة. كل انتقال آلي، ولا واحد منها يحتاج إنساناً ليتذكّر. المُدخل يعرف متى ينتهي عمله ومتى تنقضي خانته في التقويم.
الجدول @daily، الأمر يُشير إلى سكربت تقطيع، expires_at مضبوط على ما بعد آخر تشغيل متوقّع بقليل. الموعد النهائي في المُدخل — لا في وثيقة Notion، ولا في خيط Slack.
كل تشغيل يحذف شريحة من البيانات القديمة كي لا تُرهَق قاعدة البيانات. اليوم الأول قد يمسح 247 ملفاً؛ اليوم السادس فقط 1. الإيقاع محدود بما تبقّى فعلاً.
آخر كتلة في السكربت تتفقّد ما إذا كان الهدف فارغاً. إن نعم، تُطلق DELETE /entries/[self]. وإن لم تفعل لسبب ما، تُطلق expires_at شبكة الأمان بعد بضعة أيام.
محرّكان مستقلّان — تحقّق السكربت الذاتي وexpires_at على مستوى API — يتلاقيان في النتيجة نفسها: سطر في crontab لا يعيش أطول من غرضه.
Hoody Cron غلاف JSON-CRUD حول crontab النظام. POST يُنشئ المُدخل؛ DELETE يُزيله؛ expires_at هو شبكة الأمان. السكربت الذي يعمل ليلاً هو من يعرف متى انتهى — لذا هو من يستدعي 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 هو UUID الذي أعاده POST — يستطيع السكربت قراءته من ملف مرّره سطر أمر المُدخل، أو من $HOODY_ENTRY_ID وقت التشغيل. على أي حال، مُدخل cron يحذف مُدخل cron.
ليس الحذف هو ما يهمّ. بل أنه لا أحد يحتاج أن يتذكّر وجود أيّ من هذا بعد ثلاثة أشهر من الآن.
@daily يعمل كل 24 ساعة. السكربت يحذف شريحة من البيانات القديمة — بضعة آلاف من الملفات، بضعة آلاف من الصفوف — ويخرج. قاعدة البيانات تبقى هادئة؛ منحنى الحمل يبدو وكأن شيئاً لم يحدث.
expires_at في المُدخل بصيغة JSON. حين يُطلق، يُحذف السطر من crontab النظام. ثلاثة مهندسين من الآن، لا أحد يتصفّح 200 سطر متسائلاً ماذا يفعل cleanup-stale-uploads-v3 بعد.
السكربت يُرسل DELETE لنفسه ليلة انتهاء العمل. إن تخطّى خلل ذلك المسار، expires_at يُقاعد المُدخل بعد بضعة أيام. آليتان مستقلّتان؛ واحدة منهما ستُطلق.
كل مُدخل مُدار هو صفّ JSON يحقنه API في crontab النظام. التوسّع محدود بما يستطيع cron نفسه أن يحمله، لا بـ Hoody.
@daily هو الإيقاع المعتاد للتنظيف. إن احتجت تمريرات أكثر تواتراً تستطيع استخدام تعابير الخمسة حقول وصولاً إلى * * * * * — دقّة الدقيقة.
طابع زمني ISO-8601 على المُدخل. حين يمضي، يُزيل API السطر في الكنس التالي. التنظيف لا يتمدّد قطّ بعد موعده النهائي.
DELETE /users/[user]/entries/[id] من داخل الأمر قيد التشغيل يعمل لأن عفريت cron لا يقفل crontab الخاص به — API يكنس التغيير بأمان.
تعابير cron قياسية من خمسة حقول مع الماكروات (@hourly, @daily, @weekly, @monthly, @yearly). عزل لكل مستخدم؛ كل مستخدم نظام يحصل على crontab خاص به. صفحة Cron في Hoody Kit توثّق كلّاً من المُدخلات المُدارة وaccess crontab الخام إن احتجت الشكل الأقدم.
التنظيف يعمل ليلاً حتى يختفي الشيء الذي يجري تنظيفه.
في أيّ مكان يُفترض فيه بمهمة تنظيف أن تختفي من تلقاء نفسها — هذه هي الأنماط التي يحلّ هذا محلّها:
وفّر التنظيف. اضبط تاريخ تقاعده. وامشِ بعيداً.