تصور کنید یک عامل هوش مصنوعی را در یک سرور کوچک مستقر کردهاید و حالا ساعت ۳ صبح است و کل سیستم شما بدون هیچ هشداری از کار افتاده است. اگر هنوز به امید پایداریِ پیشفرضِ اسکریپتهای خود را رها کردهاید، باید بدانید که اکثر این سیستمها در نهایت به «فرآیندهای زامبی» تبدیل میشوند که در سکوت شکست میخورند و مالک سیستم تنها زمانی متوجه این کرش میشود که ایمیلی از یک مشتری دریافت کند یا متوجه شود یک Cron Job با شکست مواجه شده است. اینها همان ابزارهایی هستند که یک روز تعطیل کلون میکنید، به سیستمهای خود متصل میکنید و رهایشان میکنید چون مفید هستند، اما مکرراً دچار «شکستهای ساعت ۳ صبح» میشوند که تا زمانی که خیلی دیر نشده، نادیده گرفته میشوند.
به نقل از گزارشهای فنی منتشر شده در dev.to، ابزارهایی مانند hermes-agent با ساده کردن استقرار، محبوبیت زیادی کسب کردهاند و تنها در یک هفته بیش از ۸,۰۰۰ ستاره در گیتهاب گرفتند، اما لحظهای که نظارت انسانی متوقف شود، تبدیل به یک ریسک تبدیل میشوند. برای یک شرکت تکنفره که ۸۴ کانتینر را روی دو سرور مدیریت میکند، خطر اصلی «احمقانه» عمل کردن عامل نیست — چرا که حفاظها (Guardrails) میتوانند جلوی آن را بگیرند — بلکه فروپاشی خودِ زیرساخت است. همانطور که در بحثهای گذشتهی ما دربارهی پایداری سیستمهای عاملمحور اشاره کردیم، اشباع شدن استخر اتصالات (Connection Pool)، خروج ناگهانی کانتینر یا جهش ترافیک میتواند هر ماشینی را منجمد کند، فارغ از اینکه هوش مصنوعیِ درون آن چقدر باهوش باشد. هدف این است که از دنیایی که در آن یک کرش نیمهشب به معنای مرگ اپلیکیشن در صبح است، به دنیایی برویم که این اتفاق تنها یک خط در دفترچه ثبت عملیات (Log) باشد.
واقعیت جهش ترافیک
یک مورد واقعی را در نظر بگیرید: در ساعت ۰۰:۳۰، یک حلقه نظارتی متوجه شد که میانگین بار (Load Average) ماشینی که معمولاً روی عدد ۴ است، به ۳۳.۵۹ رسیده است. یکی از ۸۴ کانتینر وارد یک حلقه تکرار بسته (Tight Loop) شده بود. به دلیل وجود یک سیستم خودکار، این وضعیت به عنوان «قرمز» علامتگذاری شد، روتین تعمیر اجرا شد و تا ساعت ۰۱:۰۰، تمام وضعیتها دوباره «سبز» شدند.
مدیر سیستم این گزارش را هنگام صبحانه خواند. این ورودی در دفترچه عملیات با برچسب زمانی، اعداد مربوط به بار سیستم و اقدام انجام شده ثبت شده بود. این وضعیت ایدهآل است: جهش ترافیک در نیمهشب دیگر به معنای از کار افتادن اپلیکیشن و دریافت ایمیلهای اعتذار پیش از اولین فنجان قهوه نیست، بلکه فقط یک سطر در لاگ است. این پایداری نتیجه سه اسکریپت است که در مجموع کمی بیش از هزار خط Bash هستند و هر خط آنها بر اساس یک حادثه واقعی نوشته شده است.
قوانین طلایی خودترمیمسازی
اولین قدم برای پایداری، اجتناب از «حلقه ریاستارت بینهایت» است. راه ساده و بدیهی برای ساخت سیستم خودترمیمشونده این است که یک حلقه ریاستارت بنویسید: اگر چیزی شکست خورد، آن را ریاستارت کن؛ اگر باز هم شکست خورد، دوباره ریاستارت کن. اما این بدیهیترین راه برای تبدیل یک شب بد به یک فاجعه است. حلقهای که هرگز موفق نمیشود، CPU را میسوزاند، لاگها را پر میکند و مشکل واقعی را زیر تپهای از نویز پنهان میکند. یک بار اتفاق افتاد که یک حلقه با نیت خوب، یک کانتینر را ۴۰ بار ریاستارت کرد، در حالی که علت اصلی صرفاً پر شدن فضای دیسک بود.
برای جلوگیری از این وضعیت، دو قانون سختگیرانه باید اجرا شود:
- محدودیت سختگیرانه تلاشها (Hard Retry Limits): هر تلاش برای تعمیر باید بودجهای کوچک داشته باشد. وقتی بودجه تمام شد، اسکریپت متوقف شود، حادثه را «باز» علامت بزند و یک انسان را بیدار کند. این اتفاق باید بعد از سومین تلاش رخ دهد، نه صدمین بار.
- اصلاحات صرفاً موقت: یک تعمیر اضطراری همیشه باید صراحتاً موقت باشد. این کار فقط زمان میخرد و جایگزین تعمیر واقعی نمیشود. برای مثال، اگر اسکریپتی یک کانتینر پل (Bridge) را از روی ایمیج کششده محلی اجرا میکند چون ایمیج اصلی ناپدید شده است، این یک پانسمان است. حادثه باید باز بماند تا یک استقرار (Deployment) درست جایگزین آن شود. تلقی کردن یک کانتینر اضطراری به عنوان راهکار دائمی، همان میانبری است که یک شب بد را به یک اتفاق تکرار شونده تبدیل میکند.
معماری سه اسکریپتی
یک سیستم خودترمیمشونده مؤثر بر سه اسکریپت خستهکننده تکیه میکند که پیشبینیپذیری را بر خلاقیت ترجیح میدهند.
اسکریپت اول: سگ نگهبان (Watchdog)
فایل live-app-watchdog.sh با ۲۸۹ خط کد تنها یک وظیفه دارد: بررسی اینکه آیا هر اپلیکیشنی که باید کانتینری فعال داشته باشد، واقعاً دارد یا خیر. هر چند دقیقه یک بار، در تمام ساعات شبانهروز، وضعیت کانتینر، سلامت دامنه و وضعیت هدف اعلامشده را مقایسه میکند. این اسکریپت تنها در شرایط محدودی اجازه دارد کانتینر اضطراری را استارت بزند:
- هیچ بکاِندی برای سرویسدهی به دامنه فعال نباشد.
- هیچ پنجره استقرار یا تعمیراتی فعال نباشد.
- ایمیج محلی از نظر Digest و پیکربندی تأیید شده باشد.
نکته حیاتی این است که از یک قفل انحصاری (Exclusive Lock) استفاده میکند تا دو اجرای همزمانِ Watchdog، دو پل موازی ایجاد نکنند. این قفل تنها یک خط کد است، اما مهمترین خط فایل است. بدون آن، دو اجرای همپوشان میتوانستند هر کدام یک کانتینر استارت بزنند و پروکسی را با دو بکاِند که کدهای متفاوتی را اجرا میکنند، رها کنند.
اسکریپت دوم: حلقه پس از استقرار
فایل post-deploy-repair-loop.sh با ۱۸۷ خط، فشردهترین اسکریپت است. این اسکریپت بلافاصله بعد از هر استقرار اجرا میشود، زیرا یک الگوی غلط در اینجا میتواند پیش از ناهار در ۱۳ اپلیکیشن پخش شود. این اسکریپت یک چرخه چهار مرحلهای سختگیرانه را دنبال میکند:
۱. بررسی HTTP: آیا اپلیکیشن پاسخ درست میدهد؟
۲. بررسی بصری: آیا صفحه رندر شده درست به نظر میرسد یا فقط کد ۲۰۰ OK برمیگرداند؟
۳. تلاش برای اصلاح: اجرای یک راهکار از لیست کوتاه اصلاحات شناختهشده.
۴. بررسی مجدد: تکرار مراحل اول و دوم.
این حلقه حداکثر سه بار تکرار میشود. منطق آن به این صورت است: ابتدا تلاشها صفر شده و تا سقف ۳ بار، اگر بررسی HTTP و بصری موفق بود، موفقیت لاگ شده و خارج میشود؛ در غیر این صورت، تلاش افزایش یافته، خطا لاگ شده و راهکار شناخته شده اجرا میشود. در نهایت اگر باز هم شکست خورد، مورد به انسان ارجاع داده میشود.
اسکریپت سوم: تعمیر جامع
فایل smart-auto-heal.sh با ۷۱۲ خط، بزرگترین اسکریپت است. اندازه آن نشان میدهد که «بررسی سلامت و تعمیر» در واقع دهها مشکل کوچک و متفاوت است. این اسکریپت برای هر الگویی که قبلاً دیده است، یک راهکار ذخیره میکند. نمونههایی از الگوهای مدیریتشده عبارتند از:
- صفهای گیر کرده (Stuck Queue).
- اشباع استخر اتصالات.
- کانتینری با کد خروجی غیر صفر.
- ایندکس جستوجویی که ۱۷ ساعت است بازسازی نشده است.
خطر کلاسهای فرآیند
همه ریاستارتها یکسان نیستند. در ۲۹ جولای، حادثهای مربوط به یک سرور MCP (پروتکل زمینه مدل) نشان داد که کشتن یک فرآیند برای اجبار به ریاستارت میتواند مخرب باشد. غریزه هر برنامهنویسی این است که فرآیند را بکشد تا دوباره برگردد، که برای اکثر سرویسهای طولانیمدت جواب میدهد. اما سرورهای MCP از طریق لولههای ورودی و خروجی استاندارد (Stdio Pipes) با جلسه ارتباط برقرار میکنند. کشتن سرور، لوله را نابود میکند. بدون لودبالانسر، مکانیزم اتصال مجدد یا تلاش مجدد، تمام ابزارهای آن سرور تا پایان جلسه از کار میافتند.
این درس مهمی داد: اسکریپت تعمیر باید قبل از اقدام، «کلاس فرآیند» را شناسایی کند. برای یک کلاس، «کشتن و ریاستارت» یعنی بازیابی؛ برای کلاس دیگر، یعنی نابودی. به همین دلیل است که واژگان اصلاحی یک لیست سختافزاری (Hard-coded) هستند و نه یک پرامپت هوش مصنوعی. هیچکس نباید در ساعت ۲ صبح تحت فشار خلاقیت به خرج دهد، حتی اسکریپتها.
محافظت از ترمیمکننده
از آنجایی که این اسکریپتها قدرت ریاستارت کانتینرها، پاک کردن کش و استارت زدن ایمیجهای پل را دارند، پتانسیل تخریب دارند. قلابهای عامل (Agent hooks) به طور خودکار در یک Cron Job مستقل اعمال نمیشوند، بنابراین اسکریپتهای تعمیر لیست سفید (Allowlist) محدود، سیستم قفل و لاگهای تغییرناپذیر خود را دارند. یک خط قرمز محکم وجود دارد روی چیزهایی که هرگز نباید لمس شوند:
- دادههای مشتریان.
- تغییرات در Schema پایگاهداده.
- ارسال پیام به کاربران واقعی.
واژگان اصلاحی را عمداً زیرساختی و بازگشتپذیر طراحی کردهاند. این مرز است که به اپراتور اجازه میدهد در حالی که اسکریپتها در حال اجرا هستند، با خیال راحت بخوابد.
نتایج و ارتقاء
محدودیتهای تلاش بیفایده است اگر «ارتقاء به انسان» فقط یک خط در لاگ باشد. در عمل، این به معنای یک نوتیفیکیشن Push روی گوشی در عرض چند ثانیه پس از اتمام بودجه تلاشها است. این نوتیفیکیشن شامل جزئیات دقیق است: کدام اپلیکیشن شکست خورد، کدام بررسی ناموفق بود، چند بار تلاش شد و آخرین راهکار امتحان شده چه بود.
در چند ماه گذشته، داشبورد عملیات نشان میدهد که از ۱۸۷۳ تلاش، ۱۳۵۴ مورد بدون دخالت انسان با موفقیت انجام شده است — یعنی نرخ موفقیت ۹۳٪. ۷٪ باقیمانده به انسان ارجاع شدند و هر کدام با جزئیات کامل رسیدند، نه یک پیام مبهم که «یک جای کار میلنگد».
گام بعدی شما
برای کسانی که تازه یک عامل را میزبانی شخصی (Self-hosting) کردهاند، با یک حلقه تعمیر ۷۱۲ خطی شروع نکنید. کوچکتر از آنچه فکر میکنید شروع کنید:
- یک Cron Job ساده بنویسید که فقط بررسی کند مهمترین فرآیند شما در حال اجرا است یا خیر.
- اگر در حال اجرا نبود، یک بار آن را ریاستارت کنید، نتیجه را لاگ کنید و متوقف شوید.
- محدودیت تعداد تلاشها (Retry Limit) را در اولین نسخه اسکریپت خود بگنجانید.
هر بار که مشکلی پیش آمد و آن را دستی حل کردید، راهکار بعدی را اضافه کنید. در یک سال، شما هزار خط کد خودتان را خواهید داشت و هر خط یک داستان خواهد داشت. خبر خوب این است که داستانها کوتاهتر میشوند و از «اپلیکیشن تمام شب قطع بود» به یک ورودی لاگ با برچسب زمانی تبدیل میشوند. این رویکرد دستی و تدریجی برای کسانی که در محیطهای سازمانی با مقیاس بالا فعالیت میکنند، حیاتی است، چرا که تفاوتهای بنیادین میان عاملهای سفارشی و مدلهای SaaS میتواند نقطه شکست مقیاسپذیری در سازمانها باشد.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو