סוכן ה-AI שלך ב-Elevare Digital נכנס למצב חוסר פעילות (idle) מכיוון שמדיניות אבטחת רמת שורה (RLS) חדשה שהתווספה ב-PostgreSQL סיננה החוצה כל שורת עבודה, מה שגרם לתור להיראות ריק. הטעות לא נצפתה עד שהעבודות הצטברו, מה שאילץ את הצוות לעצב מחדש את האופן שבו האורקסטרטור מזהה תור ריק.
נקודת עיוורון נסתרת
ARIA, מערכת ה-AI האוטונומית של Elevare, מבצעת שאילתות (polls) בטבלת PostgreSQL עבור עבודות ממתינות. השאילתה הצליחה, החזירה אפס שורות, והסוכן "נרדם". במציאות, הטבלה הייתה מלאה. מדיניות RLS הגבילה את גישת ה-SELECT לקבוצה ספציפית של משתמשים. האורקסטרטור התחבר באמצעות service role שחסרה לו הרשאת עקיפה (bypass privilege), ולכן מסד הנתונים הסיר בשקט כל שורה מסט התוצאות. PostgreSQL מתייחס לקריאה מסוננת באותו אופן כמו לטבלה ריקה, כך שלא הופיע שום שגיאה, אזהרה או קוד כשל. הלבטה (heartbeat) תקינה מהסוכן הלא-פעיל לא רמזה על שום דבר לא תקין.
איך ה-RLS הפך תור מלא לשתיקה
RLS מוסיף פרדיקט (predicate) לכל שורה במהלך SELECT. אם הפרדיקט הוא false, השורה נעלמת מהתוצאה. הלקוח רואה רק שורות שעונות על המדיניות; הוא לעולם לא יודע שהשורות הוסתרו. עבור עובד תור (queue worker), סט תוצאות ריק נראה בדיוק כמו תור ריק באמת. האורקסטרטור הניח ש"אין שורות = אין עבודה" ונכנס ללולאת חוסר הפעילות שלו בזמן שהעבודות הצטברו מאחורי הקלעים.
הצוות גילה שמדיניות שנועדה להגביל קריאות למשתמשים בודדים תפסה בטעות גם את ה-service role עצמו. מכיוון שלתפקיד חסר מאפיין ה-"bypass RLS" המיוחד, המדיניות הוחלה על כל שאילתה שהאורקסטרטור הוציא. זה ממחיש את הטרייד-אוף הקלאסי בין אבטחה לנראות (observability): RLS מגן על נתונים מפני משתמשים לא מורשים, אך הוא גם מסיר אות כשל שימושי עבור רכיבי מערכת המסתמכים על נראות.
תבנית בדיקת ה"קנרי" (canary-check)
כדי לשבור את התלות בתוצאה ריקה ושקטה, Elevare הוסיפה בדיקת "קנרי" (canary). הזרימה החדשה היא:
- בצע שאילתה בטבלת העבודות הממתינות.
- אם מוחזרות שורות, עבד אותן כבעבר.
- אם התוצאה ריקה, בצע שאילתה שנייה מול שורת קנרי ייעודית שחייבת להתקיים תמיד.
- אם שאילתת הקנרי מחזירה את השורה הצפויה, התור ריק באמת; רשום הלבטה (heartbeat) של חוסר פעילות.
- אם גם שאילתת הקנרי לא מחזירה דבר, הסוכן "עיוור"; העלה התראה מיידית.
כעת האורקסטרטור מבחין בין שלושה מצבים:
- נמצאו עבודות – עיבוד רגיל.
- אין עבודות, הקנרי תקין – תקופת חוסר פעילות אמיתית.
- אין עבודות, הקנרי נכשל – חסימת RLS נסתרת, הפעלת התראה.
טבלת הקנרי היא שורה בודדת שלעולם אינה משתנה. ההקמה שלה ארכה כשעה, אך היא מבטלת סוג שלם של כשלים שקטים.
מה צוותים צריכים לעשות
אם אתם מריצים עובדי תור מול PostgreSQL או שירות מאוחסן הבנוי עליו (כמו Supabase), פעלו לפי הצעדים הבאים:
- השתמשו בפרטי גישה של service-role עם דגל "bypass RLS". זה מאפשר לרכיבי מערכת לראות את כל השורות ללא קשר למדיניות ברמת המשתמש.
- בצעו ביקורת (Audit) למדיניות ה-RLS כדי לוודא שאין הרשאות bypass חסרות עבור תפקידי שירות. מדיניות שנראית תקינה עבור משתמשי קצה עלולה לכלוא בטעות שירותים פנימיים.
- הוסיפו טבלת קנרי (או שורה מקבילה שתמיד קיימת) ושלבו את בדיקת הקנרי בלוגיקת חוסר הפעילות של העובד. השאילתה הנוספת היא זולה ומספקת רשת ביטחון ברורה.
הטרייד-אוף
RLS נותר כלי עוצמתי לאכיפת גישה מפורטת לנתונים. הוא מונע דליפות נתונים מקריות ותומך בארכיטקטורות מרובות-דיירים (multi-tenant) מבלי לפזר מסננים ברמת האפליקציה בכל רחבי קוד המקור. החיסרון הוא שהוא יכול להסתיר כשלים מרכיבים שמצפים מאותות "אין שורות" פשוטים לשמע "אין מה לעשות". תבנית הקנרי אינה מחלישה את ה-RLS; היא מוסיפה שלב אימות קל שמשחזר את הנראות (observability).
שורה תחתונה
מדיניות RLS נסתרת יכולה להפוך תור עמוס למבוי סתום שקט, ולהשאיר סוכני AI במצב חוסר פעילות בזמן שהעבודה מצטברת. העניקו לתפקידי שירות את הרשאת ה-bypass המתאימה וצמדו לכל קריאה של תור ריק בדיקת קנרי; צוותים יכולים לשמור על העובדים האוטונומיים שלהם אמינים ולהימנע מנקודות עיוורות יקרות.
