اگر کاربر شما ۱۰ ثانیه منتظر پاسخ یک مدل میماند و سپس صفحه را میبندد، اما سرویس شما همچنان ۳۰ ثانیه دیگر در حال پردازش است، شما در حال سوزاندن منابع سرور برای کسی هستید که دیگر وجود ندارد. این شکاف میان «محدودیت محلی» و «ضربالاجل کلی»، ریشهٔ اصلی اکثر توقفهای ناگهانی (Timeout) در اپلیکیشنهای هوش مصنوعی است.
وقتی یک کاربر منتظر پاسخ است، او با یک ضربالاجل کلی (Global Deadline) روبروست، نه مجموعهای از تنظیمات مجزای تایماوت در پنج میکروسرویس مختلف. طبق گزارشهای فنی، اگر سرویس شما یک مدل رایگان را با تایماوت ۳۰ ثانیهای فراخوانی کند اما مدل در ثانیه ۳۵ پاسخ دهد، کاربر و تمام سرویسهای بالادستی، هزینهٔ آن ۵ ثانیه اضافی را میپردازند. در واقع، یک تایماوت ۳۰ ثانیهای در سمت کلاینت، تضمینی نیست که سرویس شما متوقف نشود؛ بلکه تنها یک محدودیت محلی است که اغلب هیچکس را محافظت نمیکند.
این موضوع هنگام استفاده از مدلهای رایگان، مانند سرویسهای MonkeyCode، حیاتیتر میشود. در این پلتفرمها، دسترسی رایگان به مدلها و گزینههای سرور رایگان، مانع ورود را برای توسعهدهندگان کاهش میدهد، اما هزینهٔ پایین به معنای پیچیدگی کمتر نیست؛ بلکه این سرویسها اغلب با تأخیرهای بالا و «دمهای بلند» (Long Tails) همراه هستند. همانطور که در تحلیلهای قبلی ما دربارهی بهینهسازی استنتاج اشاره کردیم، مدیریت تأخیر در مدلهای ارزانقیمت، سختترین بخش مهندسی است. این چالشها دقیقاً همان نقاط ضعفی هستند که در بررسی تأثیر تأخیرهای P95 بر توقف خطوط تولید AI به آنها پرداختیم. در یک زنجیرهٔ معمولی، اگر سرویس A و B هر دو تایماوت ۳۰ ثانیهای داشته باشند، یک مدل کند میتواند مجموعاً ۶۰ ثانیه انتظار ایجاد کند تا سیستم بفهمد عملیات شکست خورده است. تا زمانی که خطا بازگردد، کاربری که احتمالاً پس از ۱۰ ثانیه جلسه را ترک کرده، مدتهاست که سیستم را رها کرده است.
این مطلب به عنوان یک FAQ برای ابطال باورهای غلط (Myth-busting) نوشته شده تا مدل ذهنی مدیریت تایماوت را اصلاح کند. اصلاح اصلی این است: تایماوتها محدودیتهای محلی هستند، در حالی که ضربالاجلها وعدههای پایان-به-پایان (End-to-End) محسوب میشوند. شما به هر دو نیاز دارید، اما اکثر کدها فقط اولی را پیاده میکنند.
چهار باور غلط دربارهٔ تایماوت
- باور اول: تایماوت کلاینت همان ضربالاجل است. توسعهدهندگان اغلب فکر میکنند: «تایماوت ۳۰ ثانیه است، پس تابع نمیتواند برای همیشه معلق بماند». اگرچه درست است که برای همیشه متوقف نمیشود، اما این یک تضمین ضعیف است. یک ضربالاجل واقعی از بیرون میآید: کاربری که دو ثانیه منتظر است، یک صف که پس از پنج ثانیه تخلیه میشود، یا یک SLO بالادستی که در ثانیه ۱۰ شکست میخورد. تابع شما هیچ دیدگاهی نسبت به این محدودیتهای جهانی ندارد. برای رفع این مشکل، ابتدا نام ضربالاجل را تعیین کنید، آن را به برشهای زمانی تقسیم کنید و تنها پس از آن، تایماوتهای نسبی را انتخاب کنید.
- باور دوم: تایماوتهای طولانیتر امنتر هستند. شنیدهایم که «سرورهای رایگان کند هستند، پس یک دقیقه زمان بدهید». اما این ریاضیات خطرناکی است. دو فراخوانی تو در تو که هر کدام ۶۰ ثانیه تایماوت دارند، یک پنجرهٔ بدترین حالت ۱۲۰ ثانیهای ایجاد میکنند. این پنجره رایگان نیست؛ شما در این مدت یک اتصال (Connection)، یک Worker و احتمالاً یک هندل پایگاهداده را اشغال کردهاید. یک تایماوت سخاوتمندانه، «دم بلند» تأخیر را حل نمیکند، بلکه فقط منتظر میماند تا کل آن دم طی شود. یک خطای ۵۰۴ واضح، همیشه بهتر از یک پاسخ ۲۰۰ دیرهنگام است.
- باور سوم: فقط فراخوانی مدل نیاز به محافظت دارد. بسیاری تصور میکنند DNS، تجزیهٔ JSON و ثبت لاگها سریع و بدون ریسک هستند. در واقعیت، DNS میتواند معلق شود، یک پایگاهداده سرد (Cold Database) میتواند متوقف شود و لاگها تحت فشار شدید میتوانند باعث مسدود شدن (Block) شوند. هر گام بین درخواست و پاسخ، منبعی برای تأخیر است. هیچکدام از این موارد توسط تایماوت مدل پوشش داده نمیشوند.
- باور چهارم: تایماوت اتصال (Connect Timeout) کافی است. یک سرور میتواند اتصال TCP را فوراً بپذیرد (که تایماوت اتصال را ارضا میکند) اما سپس زمان زیادی فکر کند تا اولین توکن را ارسال کند. اگر هیچ تایماوت خواندنی (Read Timeout) تنظیم نشده باشد، کد شما صرفاً در حالت خواب (Sleep) روی عملیات خواندن میماند. تایماوتهای مربوط به اتصال، خواندن و نوشتن باید از بودجهٔ کل زمانی مجزا باشند.
مدل ذهنی «بودجهٔ زمانی»
برای حل این مشکل، نویسنده مدل ذهنی «بودجه» (Budget) را پیشنهاد میکند. به جای تنظیم یک تایماوت نسبی، سیستم باید در لحظه ورود درخواست، یک ضربالاجل مطلق تعیین کند (مثلاً: request_start + 2.0s). این زمان مطلق در طول پشته (Stack) به پایین منتقل میشود. هر گام بعدی میپرسد: «چقدر از بودجه باقی مانده است؟»
اگر زمان باقیمانده صفر باشد، سرویس باید فوراً متوقف شده و خطای ۵۰۴ را به همراه دلیل آن برگرداند. این کار از مشکل «درخواستهای زامبی» جلوگیری میکند؛ وضعیتی که در آن سرور همچنان در حال پردازش درخواستی است که کلاینت مدتهاست آن را رها کرده است.
برای کسانی که از پایتون Async استفاده میکنند، این راهنما پیشنهاد میکند گامهای I/O را در asyncio.timeout با استفاده از بودجهٔ باقیمانده محاسبه شده قرار دهند. یک الگوی ارائه شده از تابع remaining(deadline) استفاده میکند تا زمان فعلی monotonic() را از ضربالاجل مطلق کسر کند. این کار کد را مجبور میکند به جای یک عدد استاتیک و دلخواه، به ضربالاجل جهانی احترام بگذارد.
تقسیمبندی دادهمحور
به جای حدس زدن مقادیر تایماوت، توسعهدهندگان باید از یک Probe (کاوشگر) برای اندازهگیری میانه (Median) و صدک ۹۰ (p90) تأخیر نقاط انتهایی خود استفاده کنند. یک Probe قابل تکرار را میتوان با گرم کردن نقطه انتهایی (مثلاً ۳ فراخوانی اولیه) و سپس اندازهگیری ۱۰ فراخوانی بعدی اجرا کرد. اگر p90 سه برابر میانه باشد، یک تایماوت ثابت ۳۰ ثانیهای کلاینت عملاً شبیه به یک بلیط بختآزمایی است.
پس از جمعآوری دادهها، بودجه کل بر اساس خروجی Probe به تخصیصهای خاص تقسیم میشود:
- برش ۱: جستوجوی DNS
- برش ۲: پیشپردازش (Preprocessing)
- برش ۳: فراخوانی مدل
- برش ۴: اعتبارسنجی و نوشتن پاسخ
مدیریت اتمام بودجه
وقتی بودجه تمام میشود، اقدام شما باید بر اساس شواهدی باشد که در Probe یافت شده است:
- شکست سریع اتصال (OSError در کمتر از ۵۰ میلیثانیه): یک بار تلاش مجدد (Retry) کنید، زیرا شکستهای اتصال اغلب گذرا هستند.
- تایماوت خواندن در حالی که اولین توکن رسیده است (جریان دادههای ناقص): تلاش مجدد نکنید. وضعیت در این حالت مبهم است؛ خطای ۵۰۴ برگردانید.
- تایماوت خواندن در حالی که هیچ چیز نرسیده است (۰ بایت در پنجره زمانی): تنها در صورتی که فراخوان اجازه دهد، یک بار تلاش مجدد کنید.
- اتمام کامل بودجه (تأیید شده توسط Median/p90): فوراً متوقف شوید. سیستم را به یک پاسخ جایگزین (Fallback) یا خطا تنزل دهید.
این رویکرد برای کارهای دستهای (Batch) که در آن انتظار ۶۰ ثانیهای در ساعت ۲ صبح پذیرفتنی است، یا برای زنجیرههای تکگامه که در آنها یک تایماوت عملاً برابر با یک ضربالاجل است، ضروری نیست. اما برای هر اپلیکیشن AI کاربرمحور، مدیریت بودجه تنها راه تضمین پایداری است.
برای توسعهدهندگان، این تغییر، فرض بنیادی ادغام AI را تغییر میدهد. تمرکز را از «امید به اینکه مدل به اندازه کافی سریع باشد» به «کنترل دقیق نحوه شکست سیستم» منتقل میکند. این انضباط باعث میشود فراخوانیهای لایههای پولی (Paid-tier) خستهکننده و پیشبینیپذیر به نظر برسند—و در مهندسی تولید (Production Engineering)، «خستهکننده بودن» هدف نهایی است.
گام بعدی شما
- تأخیرهای p90 سرویسهای خود را اندازهگیری کنید تا متوجه شوید چند درصد از کاربران شما در «دم بلند» تأخیرها گرفتارند.
- در لایههای API، ضربالاجل مطلق را به جای تایماوتهای نسبی در Headerها منتقل کنید.
- برای فراخوانیهای مدلهای رایگان، حتماً Read Timeout را مجزا از Connect Timeout تعریف کنید.
اما مدیریت این بودجه در محیطهای توزیعشده پیچیدگیهای بیشتری دارد — به تحلیل ما دربارهی پروتکلهای ارتباطی میکروسرویسها مراجعه کنید.




گفتگو