Ваш AI-агент у Elevare Digital перейшов у режим очікування, оскільки нещодавно додана політика безпеки на рівні рядків (RLS) у PostgreSQL відфільтрувала всі рядки з завданнями, через що черга здалася порожньою. Помилка залишалася непоміченою, поки завдання не почали накопичуватися, що змусило команду переглянути спосіб, у який оркестратор визначає порожню чергу.

Прихована сліпа зона

ARIA, автономна AI-система від Elevare, опитує таблицю PostgreSQL на наявність незавершених завдань. Запит пройшов успішно, повернув нуль рядків, і агент «заснув». Насправді таблиця була повною. Політика RLS обмежувала доступ SELECT певним набором користувачів. Оркестратор підключався за допомогою сервісної ролі, яка не мала привілею bypass, тому база даних безшумно видалила кожен рядок із результату запиту. PostgreSQL сприймає відфільтроване читання так само, як порожню таблицю, тому жодних помилок, попереджень чи кодів збою не з'являлося. Стабільний сигнал heartbeat від бездіяльного агента не давав жодного натяку на те, що щось пішло не так.

Як RLS перетворила повну чергу на тишу

RLS додає предикат до кожного рядка під час виконання SELECT. Якщо предикат хибний (false), рядок зникає з результату. Клієнт бачить лише ті рядки, які відповідають політиці; він ніколи не дізнається, що деякі рядки були приховані. Для воркера черги порожній набір результатів виглядає точно так само, як справді порожня черга. Оркестратор вирішив, що «немає рядків = немає роботи», і перейшов у цикл очікування, поки завдання накопичувалися за лаштунками.

Команда виявила, що політика, призначена для обмеження доступу до даних окремих користувачів, ненавмисно зачепила саму сервісну роль. Оскільки роль не мала спеціального атрибута «bypass RLS», політика застосовувалася до кожного запиту, який надсилав оркестратор. Це ілюструє класичний компроміс між безпекою та спостережністю (observability): RLS захищає дані від неавторизованих користувачів, але водночас позбавляє корисного сигналу про збій системні компоненти, які залежать від видимості даних.

Патерн «canary-check» (перевірка канарейкою)

Щоб позбутися залежності від безшумного порожнього результату, Elevare додала перевірку «канарейкою». Новий процес виглядає так:

  1. Запит до таблиці незавершених завдань.
  2. Якщо рядки повернуто, обробляйте їх як і раніше.
  3. Якщо результат порожній, виконайте другий запит до спеціального рядка-канарейки, який має існувати завжди.
  4. Якщо запит канарейки повертає очікуваний рядок, черга справді порожня; зафіксуйте idle heartbeat.
  5. Якщо запит канарейки також нічого не повертає, агент «сліпий»; негайно активуйте сповіщення.

Тепер оркестратор розрізняє три стани:

  • Завдання знайдено – звичайна обробка.
  • Завдань немає, канарейка OK – справжній період очікування.
  • Завдань немає, канарейка не пройшла перевірку – приховане блокування RLS, запуск сповіщення.

Таблиця-канарейка — це один рядок, який ніколи не змінюється. Її налаштування зайняло близько години, але це усуває цілий клас безшумних збоїв.

Що варто робити командам

Якщо ви запускаєте воркери черги для PostgreSQL або хостованого сервісу на його основі (наприклад, Supabase), дотримуйтесь цих кроків:

  • Використовуйте облікові дані сервісної ролі (service-role) з прапорцем «bypass RLS». Це дозволить системним компонентам бачити всі рядки незалежно від політик на рівні користувачів.
  • Проводьте аудит політик RLS на предмет відсутності дозволів bypass для сервісних ролей. Політика, яка виглядає правильно для кінцевих користувачів, може ненавмисно заблокувати внутрішні сервіси.
  • Додайте таблицю-канарейку (або еквівалентний рядок, що завжди присутній) і впровадьте перевірку канарейки в логіку очікування воркера. Додатковий запит коштує дешево і забезпечує надійну мережу безпеки.

Компроміс

RLS залишається потужним інструментом для забезпечення детального доступу до даних. Він запобігає випадковим витокам даних і підтримує багатоорендну (multi-tenant) архітектуру, не розпилюючи фільтри на рівні додатка по всьому коду. Недоліком є те, що він може приховувати збої від компонентів, які очікують, що простий сигнал «немає рядків» означатиме «немає роботи». Патерн «канарейки» не послаблює RLS; він додає легкий крок верифікації, який відновлює спостережність.

Висновок

Прихована політика RLS може перетворити завантажену чергу на безшумний глухий кут, залишаючи AI-агентів бездіяльними, поки робота накопичується. Надавайте сервісним ролям належний привілей bypass і поєднуйте кожен запит до порожньої черги з перевіркою канарейки; так команди зможуть забезпечити коректну роботу своїх автономних воркерів і уникнути дорогих сліпих зон.