AI agent tại Elevare Digital đã rơi vào trạng thái nghỉ (idle) vì một chính sách bảo mật cấp hàng (RLS) mới được thêm vào của PostgreSQL đã lọc mất mọi hàng công việc, khiến hàng đợi trông như bị trống. Sai lầm này không được phát hiện cho đến khi công việc bị dồn ứ, buộc đội ngũ phải thiết kế lại cách bộ điều phối (orchestrator) phát hiện hàng đợi trống.

Điểm mù ẩn giấu

ARIA, hệ thống AI tự trị của Elevare, thực hiện truy vấn (poll) một bảng PostgreSQL để tìm các công việc đang chờ. Truy vấn đã thành công, trả về không có hàng nào, và agent đã "đi ngủ". Trên thực tế, bảng đó vẫn đầy. Một chính sách RLS đã giới hạn quyền SELECT cho một nhóm người dùng cụ thể. Bộ điều phối đã kết nối bằng một service role thiếu quyền bypass, vì vậy cơ sở dữ liệu đã âm thầm loại bỏ mọi hàng khỏi tập kết quả. PostgreSQL xử lý một lần đọc bị lọc giống như một bảng trống, vì vậy không có lỗi, cảnh báo hay mã thất bại nào xuất hiện. Một tín hiệu heartbeat khỏe mạnh từ agent đang nghỉ không hề cho thấy có điều gì bất thường.

Cách RLS biến một hàng đợi đầy thành sự im lặng

RLS thêm một điều kiện (predicate) vào mỗi hàng trong quá trình SELECT. Nếu điều kiện đó sai, hàng đó sẽ biến mất khỏi kết quả. Client chỉ thấy những hàng thỏa mãn chính sách; nó không bao giờ biết rằng các hàng khác đã bị ẩn đi. Đối với một worker hàng đợi, một tập kết quả trống trông hoàn toàn giống như một hàng đợi thực sự trống. Bộ điều phối giả định “không có hàng = không có việc” và đi vào vòng lặp nghỉ trong khi các công việc đang tích tụ âm thầm phía sau.

Đội ngũ phát hiện ra rằng một chính sách vốn nhằm giới hạn phạm vi đọc cho từng người dùng đã vô tình bao hàm cả chính service role đó. Vì role này thiếu thuộc tính đặc biệt “bypass RLS”, chính sách đã áp dụng cho mọi truy vấn mà bộ điều phối thực hiện. Điều này minh họa cho sự đánh đổi kinh điển giữa bảo mật và khả năng quan sát (security-vs-observability): RLS bảo vệ dữ liệu khỏi những người dùng không được phép, nhưng nó cũng loại bỏ một tín hiệu thất bại hữu ích cho các thành phần hệ thống vốn dựa vào khả năng hiển thị dữ liệu.

Mô hình kiểm tra canary (canary-check pattern)

Để phá vỡ sự phụ thuộc vào kết quả trống âm thầm, Elevare đã thêm một bước kiểm tra “canary”. Quy trình mới là:

  1. Truy vấn bảng pending-jobs.
  2. Nếu có hàng trả về, hãy xử lý chúng như trước.
  3. Nếu kết quả trống, hãy thực hiện truy vấn thứ hai vào một hàng canary chuyên dụng luôn luôn phải tồn tại.
  4. Nếu truy vấn canary trả về hàng như mong đợi, hàng đợi thực sự trống; ghi nhật ký (log) một heartbeat idle.
  5. Nếu truy vấn canary cũng không trả về gì, agent đang bị “mù”; hãy phát cảnh báo ngay lập tức.

Giờ đây, bộ điều phối phân biệt được ba trạng thái:

  • Tìm thấy công việc – xử lý bình thường.
  • Không có công việc, canary OK – giai đoạn nghỉ thực sự.
  • Không có công việc, canary thất bại – bị chặn bởi RLS, kích hoạt cảnh báo.

Bảng canary là một hàng duy nhất không bao giờ thay đổi. Việc thiết lập nó mất khoảng một giờ, nhưng nó loại bỏ hoàn toàn một loại lỗi âm thầm.

Những gì các đội ngũ nên làm

Nếu bạn chạy các queue worker với PostgreSQL hoặc một dịch vụ được xây dựng trên đó (như Supabase), hãy thực hiện các bước sau:

  • Sử dụng thông tin xác thực service-role với cờ “bypass RLS”. Điều này cho phép các thành phần hệ thống thấy tất cả các hàng bất kể các chính sách ở cấp người dùng.
  • Kiểm tra (Audit) các chính sách RLS để đảm bảo không thiếu quyền bypass cho các service role. Một chính sách trông có vẻ đúng cho người dùng cuối có thể vô tình làm kẹt các dịch vụ nội bộ.
  • Thêm một bảng canary (hoặc một hàng luôn hiện diện tương đương) và đưa bước kiểm tra canary vào logic nghỉ của worker. Truy vấn bổ sung này rất rẻ và cung cấp một lưới an toàn rõ ràng.

Sự đánh đổi

RLS vẫn là một công cụ mạnh mẽ để thực thi quyền truy cập dữ liệu chi tiết. Nó ngăn chặn rò rỉ dữ liệu vô ý và hỗ trợ kiến trúc đa người dùng (multi-tenant) mà không cần rải rác các bộ lọc ở cấp ứng dụng khắp mã nguồn. Nhược điểm là nó có thể che giấu các lỗi đối với các thành phần vốn mong đợi tín hiệu “không có hàng” đơn giản có nghĩa là “không có việc gì để làm”. Mô hình canary không làm yếu đi RLS; nó thêm vào một bước xác minh nhẹ nhàng giúp khôi phục khả năng quan sát.

Bài học rút ra

Một chính sách RLS bị ẩn có thể biến một hàng đợi bận rộn thành một ngõ cụt âm thầm, khiến các AI agent rơi vào trạng thái nghỉ trong khi công việc bị dồn ứ. Hãy cấp cho các service role quyền bypass thích hợp và kết hợp mọi lần đọc hàng đợi trống với một bước kiểm tra canary; các đội ngũ có thể giữ cho các worker tự trị của họ hoạt động chính xác và tránh được những điểm mù tốn kém.