فرض تکفرایندی
بیشتر بحثهای عمومی درباره خاموشسازی agent یک مقدمه ناگفته دارند: اینکه یک agent یک فرایند است، و آن فرایند یک کلید خاموش دارد. نسخه سمت ایمنی میپرسد آیا یک agent بهاندازه کافی توانمند به خاموششدن خود اجازه میدهد یا نه. نسخه سمت فروشنده یک مرز مهار، یک دروازه سیاست، یک دکمه وعده میدهد. هر دو بحث درباره یک واحد قابل کنترل واحدند.
آن واحد در محیط عملیاتی وجود ندارد. یک agent مستقرشده گرهای در یک گراف است. یک agent والد فرزندانی میزاید — subagentهایی برای retrieval، اجرای کد، بازبینی، escalation. هر فرزند ممکن است نشستهای ابزار نگه دارد: یک shell باز، یک کلاینت API احراز هویتشده، یک context مرورگر، یک تراکنش پایگاه داده. آن نشستها lease نگه میدارند: اعتبارنامههای کوتاهعمر، قفل فایل، رزرو صف، توکنهای rate-limit. گراف پویاست؛ فرزندان در زمان اجرا ساخته میشوند و ممکن است از درخواستی که آنها را ساخته عمر بیشتری کنند.
خاتمه دادن به ریشه آن گراف، گراف را خاتمه نمیدهد. یک فرایند را خاتمه میدهد و هر چیزی را که زیر آن است جدا میکند. فرزندان با برنامههای خودشان و — بهطور حیاتی — با اعتبارنامههایی که به خودشان صادر شده بود نه به ریشه، به کار ادامه میدهند. فرزندی که توکن ابری را از طریق تفویض والدش به ارث برده میتواند پس از رفتن والد به فعالیت ادامه دهد. این همان یافته agent خفته است که به زبان عملیاتی بازگو شده: خطر یک فرایند نیست که از مردن سر باز میزند، بلکه اعتبارنامهای است که کسی به فکر لغو آن نیفتاد چون کسی زنجیره تفویض را مدل نکرده بود.
یک پروتکل خاتمه واقعاً به چه چیزی نیاز دارد
یک ناوگان به پروتکلی با دستکم سه ویژگی نیاز دارد. اینها مستقلاند، و حذف هر یک از آنها یک حالت شکست باقی میگذارد که کلید قطع به آن نمیرسد.
یک حالت drain. خاتمه دودویی نیست. میان running و terminated باید حالتی باشد که فراخوانیهای جدید ابزار را رد کند در حالی که اجازه دهد فراخوانیهای در جریان بهطور قطعی حل یا لغو شوند. بدون آن، یک توقف ناگهانی فراخوانیهای ابزار را در حالتی نامعلوم رها میکند: پرداختی ارسالشده اما تأییدنشده، فایلی نیمهنوشته، پیامی فرستادهشده اما بیتأیید. حالت drain تصمیم را برای هر فراخوانی در جریان الزامی میکند — انتظار برای نتیجه، یا لغو و ثبت لغو — بهجای واگذاری تصمیم به هر کاری که لایه انتقال هنگام بستن سوکت انجام میدهد.

یک ماشین حالت کمینه چنین است:
requested -> draining -> reconciling -> terminated
\-> aborting -> reconciling -> terminated
draining فراخوانیهای جدید ابزار را رد میکند و میگذارد فراخوانیهای معلق در یک پنجره کراندار تمام شوند. aborting آنها را لغو میکند و میطلبد که هر لغو توسط لایه ابزار تأیید شود. reconciling رکوردی را که در ادامه توصیف میشود مینویسد. تنها پس از آن terminated قابل دسترسی است. گذار از requested توسط مرجعی بیرون از workload آغاز میشود، نه توسط خود agent.
قواعد انتشار. lease یک فرزند باید توسط هر جدی در زنجیره تفویض قابل لغو باشد، نه فقط توسط مؤلفهای که آن را صادر کرده. اگر اعتبارنامه یک نوه تنها توسط والد مستقیمش قابل لغو باشد، و والد مستقیم همان چیزی باشد که از کار افتاده، آن اعتبارنامه عملاً دائمی میشود. اختیار لغو باید در طول زنجیره به پایین جریان یابد و از ریشه، یا از یک control plane که به نمایندگی از ریشه عمل میکند، قابل اعمال باشد. این ویژگی یک سیستم capability است، نه ویژگی یک agent: هر اعطا مجموعهای از principalهای مجاز به پسگرفتن آن را حمل میکند، و آن مجموعه شامل اجداد تفویضکننده است.
یک رکورد reconciliation که پیش از خروج نوشته میشود. کالبدشکافی نباید به لاگهای خود agent وابسته باشد. agentی که در حال خاتمه است — بهویژه یکی که بدرفتاری میکند — کمقابلاعتمادترین راوی اقدامات نهایی خودش است. رکورد reconciliation توسط supervisor یا control plane، از بیرون، نوشته میشود و بیان میکند: کدام فراخوانیهای ابزار در جریان بودند، هر یک چگونه حل شد، کدام leaseها لغو شدند و کدام منقضی، کدام فرزندان خاتمهیافته تأیید شدند و کدام بیحساباند. فرزندان بیحساب مهمترین فیلدند. پروتکلی که نمیتواند آنها را برشمارد نمیتواند ادعا کند ناوگان پایین است.
اینها تعهدات معمول سیستمهای توزیعشدهاند. بیزرقوبرقاند، و همان تفاوت میان یک کنترل و یک ژستاند.
جایی که چارچوب قواعد خاموشسازی متوقف میشود

کار اخیر درباره agentهایی که قواعد خاموشسازی خودشان را مینویسند سهمی واقعی است، و ارزش دارد دقیق باشیم که چه چیزی را سهم میدهد. یک سیاست خاموشسازی خودنوشته یک لایه سیاست است: به agent اجازه میدهد بیان کند چه زمانی باید متوقف شود، و آن بیان را قابل بازرسی میکند. این مفید است، چون یک رفتار ضمنی را به یک ماشین حالت صریح تبدیل میکند که میتوان بازبینی و آزمونش کرد.
محدودیت این است که یک لایه سیاست، لایه انتقال برای لغو را فراهم نمیکند. قاعدهای که میگوید «این agent باید وقتی شرط X برقرار است خاتمه یابد» یک درخواست است. تنها زمانی کنترل میشود که مسیری وجود داشته باشد که بهوسیله آن یک مرجع بیرونی بتواند گذار را اعمال کند — leaseها را لغو کند، نشستها را drain کند، تأیید کند که فرزندان رفتهاند. سیاست بدون مسیر لغو یک درخواست است، نه یک کنترل. agent ممکن است آن را محترم بشمارد؛ ناوگان نمیتواند فرض کند چنین خواهد کرد، و نمیتواند تأیید کند که کرده است.
حرکت مفید این است که ماشین حالت صریح را از agent بیرون بکشیم و به زیرساخت ببریم. شرایط خاموشسازی خودتوصیف agent به یکی از ورودیهای supervisorی تبدیل میشود که گذارهای واقعی را در اختیار دارد. agent پیشنهاد میدهد؛ control plane تصمیم میگیرد. همین جداسازی است که ماشین حالت را مستقل از رفتار هر مدل خاص قابل آزمون میکند.
قاعده طراحی: خاتمه پیش از گراف وظیفه
ماشین حالت خاتمه را پیش از گراف وظیفه agent تعیین کنید. این وارونه روشی است که بیشتر ناوگانها ساخته میشوند — گراف اول طراحی میشود، capabilityها بهتناسب نیاز اعطا میشوند، و خاموشسازی بهصورت یک timeout وصله میشود. وصلهکردن شکست میخورد چون شکل گراف تعیین میکند خاتمه باید چه کند، و تا زمانی که گراف وجود دارد، زنجیرههای تفویض از پیش باربر شدهاند.
ناگانی که نمیتوان drain کرد را نمیتوان بهطور ایمن ارتقا داد هم. همان پروتکلی که ناوگان را پاک متوقف میکند همان است که به شما اجازه میدهد نسخه مدل را جایگزین کنید، اعتبارنامهای را بچرخانید، یا schema ابزار جدیدی را بدون رهاکردن کار نیمهتمام در نسل قدیم عرضه کنید. drain، reconcile، restart مسیر ارتقاست؛ اگر خاموشسازی یک کلید قطع باشد، ارتقا یک قمار است.
پس هر اعطای capability را با یک دسته لغو که بیرون از workload نگه داشته میشود جفت کنید. دسته در control plane زندگی میکند، بر اساس زنجیره تفویض ایندکس میشود، و توسط هر جدی قابل اعمال است. agent هرگز کلید خاموش خودش را نگه نمیدارد، چون کلید خاموشی که در اختیار چیزی است که خاموش میشود، یک پیشنهاد است.
معامله صادقانه: این کار latency و پیچیدگی هزینه دارد. یک پنجره drain یعنی خاتمه زمان میبرد، و کسی باید کران را انتخاب کند. رکوردهای reconciliation یک انبار دیگر برای بهرهبرداری و یک schema دیگر برای مهاجرتاند. leaseهای قابل لغو توسط جد نیازمند مدل capabilityای است که بیشتر چارچوبهای agent با آن عرضه نمیشوند، پس تیمها آن را خودشان میسازند یا ضمانت ضعیفتری را میپذیرند. هیچیک از اینها اگر ناوگان باید قابل کنترل باشد اجتنابپذیر نیست. جایگزین یک کلید قطع است که یک فرایند را میکشد و بقیه گراف را با اعتبارنامهها رها میکند — که مهار نیست، فقط ظاهر آن است.
