Ваш ИИ-агент в Elevare Digital перешел в режим ожидания, потому что недавно добавленная политика безопасности на уровне строк (RLS) в PostgreSQL отфильтровала все строки с задачами, из-за чего очередь казалась пустой. Ошибка оставалась незамеченной, пока задачи не начали накапливаться, что вынудило команду пересмотреть механизм определения пустой очереди оркестратором.
Скрытая слепая зона
ARIA, автономная ИИ-система Elevare, опрашивает таблицу PostgreSQL на наличие ожидающих задач. Запрос прошел успешно, вернул ноль строк, и агент «уснул». На самом деле таблица была заполнена. Политика RLS ограничивала доступ SELECT определенным набором пользователей. Оркестратор подключался с использованием сервисной роли (service role), у которой отсутствовало право обхода (bypass privilege), поэтому база данных молча удаляла каждую строку из результирующего набора. PostgreSQL обрабатывает отфильтрованное чтение так же, как и пустую таблицу, поэтому никаких ошибок, предупреждений или кодов сбоя не появлялось. Стабильный heartbeat (сигнал активности) от бездействующего агента не давал никаких намеков на то, что что-то идет не так.
Как RLS превратила полную очередь в тишину
RLS добавляет предикат к каждой строке во время выполнения SELECT. Если предикат ложен, строка исчезает из результата. Клиент видит только те строки, которые соответствуют политике; он даже не подозревает, что часть строк была скрыта. Для обработчика очереди пустой набор результатов выглядит точно так же, как действительно пустая очередь. Оркестратор предположил, что «нет строк = нет работы», и перешел в цикл ожидания, в то время как задачи накапливались «за кулисами».
Команда обнаружила, что политика, предназначенная для ограничения области чтения конкретными пользователями, непреднамеренно затронула саму сервисную роль. Поскольку у этой роли отсутствовал специальный атрибут «bypass RLS», политика применялась к каждому запросу, который отправлял оркестратор. Это иллюстрирует классический компромисс между безопасностью и наблюдаемостью (observability): RLS защищает данные от неавторизованных пользователей, но при этом она лишает полезного сигнала о сбое системные компоненты, которые полагаются на видимость данных.
Паттерн «проверка канарейкой» (canary-check)
Чтобы разорвать зависимость от «молчаливого» пустого результата, Elevare добавила проверку «канарейкой». Новый процесс выглядит так:
- Выполнить запрос к таблице ожидающих задач.
- Если строки возвращены, обрабатывать их как обычно.
- Если результат пуст, выполнить второй запрос к специальной строке-канарейке, которая должна существовать всегда.
- Если запрос «канарейки» возвращает ожидаемую строку, очередь действительно пуста; зафиксировать сигнал idle heartbeat.
- Если запрос «канарейки» также ничего не возвращает, значит, агент «ослеп»; немедленно отправить оповещение.
Теперь оркестратор различает три состояния:
- Задачи найдены — обычная обработка.
- Задач нет, канарейка в норме — действительно период простоя.
- Задач нет, канарейка не прошла — скрытая блокировка RLS, запуск оповещения.
Таблица-канарейка — это одна строка, которая никогда не меняется. Ее настройка заняла около часа, но это устранило целый класс скрытых сбоев.
Что следует делать командам
Если вы запускаете обработчики очередей в PostgreSQL или в облачном сервисе на его основе (например, Supabase), следуйте этим шагам:
- Используйте учетные данные сервисной роли (service-role) с флагом «bypass RLS». Это позволит системным компонентам видеть все строки независимо от политик пользовательского уровня.
- Проверяйте политики RLS на наличие недостающих разрешений на обход (bypass) для сервисных ролей. Политика, которая кажется корректной для конечных пользователей, может непреднамеренно блокировать внутренние сервисы.
- Добавьте таблицу-канарейку (или эквивалентную всегда присутствующую строку) и включите проверку «канарейки» в логику простоя обработчика. Дополнительный запрос стоит дешево и обеспечивает надежную страховку.
Компромисс
RLS остается мощным инструментом для обеспечения тонкой настройки доступа к данным. Он предотвращает случайные утечки данных и поддерживает многоарендные (multi-tenant) архитектуры, избавляя от необходимости разбрасывать фильтры на уровне приложения по всей кодовой базе. Недостаток заключается в том, что он может скрывать сбои от компонентов, которые интерпретируют простой сигнал «нет строк» как «нечего делать». Паттерн «канарейки» не ослабляет RLS; он добавляет легкий этап верификации, который восстанавливает наблюдаемость.
Итог
Скрытая политика RLS может превратить загруженную очередь в «тихий тупик», оставляя ИИ-агентов бездействующими, пока работа накапливается. Предоставьте сервисным ролям надлежащее право обхода и дополняйте каждое чтение пустой очереди проверкой «канарейки»; так команды смогут обеспечить корректную работу своих автономных агентов и избежать дорогостоящих слепых зон.
