عامل هوش مصنوعی شما در Elevare Digital به دلیل اضافه شدن یک سیاست جدید امنیت سطح سطر (RLS) در PostgreSQL که تمام سطرهای مربوط به وظایف (jobs) را فیلتر کرده بود، در حالت انتظار (idle) قرار گرفت و باعث شد صف خالی به نظر برسد. این اشتباه تا زمانی که وظایف انباشته شدند، نادیده گرفته شد و در نهایت تیم را مجبور کرد تا نحوه تشخیص صف خالی توسط ارکستراتور (orchestrator) را بازطراحی کند.

نقطه کور پنهان

ARIA، سیستم هوش مصنوعی خودمختار Elevare، یک جدول PostgreSQL را برای یافتن وظایف در انتظار (pending jobs) پایش می‌کند. پرس‌وجو (query) با موفقیت انجام شد، صفر سطر بازگرداند و عامل هوش مصنوعی به حالت خواب رفت. در واقعیت، جدول پر بود. یک سیاست RLS، دسترسی SELECT را به مجموعه خاصی از کاربران محدود کرده بود. ارکستراتور با یک service role متصل شده بود که فاقد امتیاز دور زدن (bypass privilege) بود، بنابراین پایگاه داده بی‌صدا تمام سطرها را از مجموعه نتایج حذف کرد. PostgreSQL یک خواندنِ فیلتر شده را دقیقاً مشابه یک جدول خالی در نظر می‌گیرد، بنابراین هیچ خطا، هشدار یا کد شکستی ظاهر نشد. ارسال ضربان قلب (heartbeat) سالم از سوی عامل در حالت انتظار، هیچ نشانه‌ای از بروز مشکل ارائه نمی‌داد.

چگونه RLS یک صف پر را به سکوت تبدیل کرد

RLS در حین اجرای SELECT، یک گزاره (predicate) را به هر سطر اضافه می‌کند. اگر گزاره نادرست باشد، آن سطر از نتیجه حذف می‌شود. کلاینت فقط سطرهایی را می‌بیند که سیاست را برآورده می‌کنند؛ کلاینت هرگز نمی‌داند که سطرهایی پنهان شده‌اند. برای یک کارگر صف (queue worker)، یک مجموعه نتیجه خالی دقیقاً شبیه به یک صف واقعاً خالی به نظر می‌رسد. ارکستراتور با این فرض که «هیچ سطری وجود ندارد = کاری برای انجام نیست»، وارد حلقه انتظار (idle loop) خود شد، در حالی که وظایف در پشت صحنه در حال انباشته شدن بودند.

تیم متوجه شد سیاستی که هدفش محدود کردن خواندن‌ها به کاربران انفرادی بود، به طور ناخواسته خودِ service role را نیز شامل شده است. از آنجایی که این نقش فاقد ویژگی خاص "bypass RLS" بود، سیاست مذکور بر هر پرس‌وجویی که ارکستراتور صادر می‌کرد اعمال می‌شد. این موضوع نشان‌دهنده یک موازنه کلاسیک میان امنیت و مشاهده‌پذیری (observability) است: RLS از داده‌ها در برابر کاربران غیرمجاز محافظت می‌کند، اما در عین حال یک سیگنال شکست مفید را برای اجزای سیستمی که به مشاهده‌پذیری (visibility) متکی هستند، از بین می‌برد.

الگوی بررسی قناری (canary-check pattern)

برای شکستن وابستگی به یک نتیجه خالی و بی‌صدا، Elevare یک بررسی «قناری» (canary) اضافه کرد. جریان جدید به این صورت است:

۱. جدول وظایف در انتظار (pending-jobs) را پرس‌وجو کنید. ۲. اگر سطری بازگردانده شد، مانند قبل آن‌ها را پردازش کنید. ۳. اگر نتیجه خالی بود، پرس‌وجوی دومی را برای یک سطر اختصاصی «قناری» که همیشه باید وجود داشته باشد، اجرا کنید. ۴. اگر پرس‌وجوی قناری سطر مورد انتظار را برگرداند، صف واقعاً خالی است؛ یک heartbeat برای حالت بیکاری ثبت کنید. ۵. اگر پرس‌وجوی قناری نیز چیزی برنگرداند، عامل هوش مصنوعی دچار «کوری» شده است؛ بلافاصله هشدار صادر کنید.

اکنون ارکستراتور سه حالت را تشخیص می‌دهد:

  • وظایف یافت شد – پردازش عادی.
  • وظیفه‌ای نیست، قناری OK است – دوره بیکاری واقعی.
  • وظیفه‌ای نیست، قناری شکست خورد – مسدود شدن توسط RLS، فعال‌سازی هشدار.

جدول قناری شامل یک سطر واحد است که هرگز تغییر نمی‌کند. راه‌اندازی آن حدود یک ساعت زمان برد، اما یک کلاس کامل از شکست‌های بی‌صدا را از بین می‌برد.

تیم‌ها باید چه کنند

اگر شما کارگرهای صف را روی PostgreSQL یا یک سرویس میزبانی‌شده بر پایه آن (مانند Supabase) اجرا می‌کنید، این مراحل را دنبال کنید:

  • از یک اعتبارنامه service-role با پرچم "bypass RLS" استفاده کنید. این کار به اجزای سیستم اجازه می‌دهد بدون توجه به سیاست‌های سطح کاربر، تمام سطرها را ببینند.
  • سیاست‌های RLS را بازرسی (audit) کنید تا از نبود مجوزهای bypass برای نقش‌های سرویس اطمینان حاصل کنید. سیاستی که برای کاربران نهایی درست به نظر می‌رسد، ممکن است به طور ناخواسته سرویس‌های داخلی را گرفتار کند.
  • یک جدول قناری اضافه کنید (یا یک سطر معادل که همیشه حضور دارد) و بررسی قناری را در منطق بیکاری (idle logic) کارگر بگنجانید. این پرس‌وجوی اضافی هزینه کمی دارد و یک شبکه ایمنی شفاف فراهم می‌کند.

موازنه

RLS همچنان ابزاری قدرتمند برای اعمال دسترسی‌های دقیق به داده‌ها است. این ابزار از نشت تصادفی داده‌ها جلوگیری می‌کند و از معماری‌های چندمستاجری (multi-tenant) بدون پراکنده کردن فیلترهای سطح اپلیکیشن در سراسر کد پشتیبانی می‌کند. نقطه ضعف آن این است که می‌تواند شکست‌ها را از اجزایی که انتظار دارند سیگنال ساده‌ی «هیچ سطری وجود ندارد» به معنای «کاری برای انجام نیست» باشد، پنهان کند. الگوی قناری، RLS را تضعیف نمی‌کند؛ بلکه یک مرحله تأیید سبک اضافه می‌کند که مشاهده‌پذیری را بازیابی می‌کند.

نتیجه‌گیری

یک سیاست پنهان RLS می‌تواند یک صف شلوغ را به یک بن‌بست بی‌صدا تبدیل کند و عامل‌های هوش مصنوعی را در حالی که کارها در حال انباشته شدن هستند، در حالت بیکاری رها کند. با اعطای امتیاز bypass مناسب به نقش‌های سرویس و همراه کردن هر خواندنِ صفِ خالی با یک بررسی قناری، تیم‌ها می‌توانند کارگرهای خودمختار خود را دقیق نگه داشته و از نقاط کور پرهزینه جلوگیری کنند.