Với SELECT ... FOR UPDATE trần, mọi worker cùng nhắm hàng cũ nhất nên chỉ một worker chạy, số còn lại xếp hàng chờ đúng hàng đó. Hai bổ ngữ thay đổi hành vi chờ:
SKIP LOCKED— bỏ qua các hàng đang bị khoá và lấy hàng kế tiếp còn rảnh. Đây là cách chuẩn để nhiều worker rút job song song.NOWAIT— không chờ, gặp hàng đang khoá thì ném lỗi ngay. Dùng khi bạn muốn thất bại nhanh và báo lại cho người dùng ("bản ghi đang được người khác chỉnh sửa") thay vì để request treo.
sql
BEGIN;
UPDATE jobs SET status = 'running'
WHERE id = (
SELECT id FROM jobs
WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED
LIMIT 1
)
RETURNING *;
COMMIT;Điểm cần nhớ:
- SKIP LOCKED cho tính chất "mỗi job đúng một worker" mà không cần broker riêng — đủ dùng cho phần lớn hàng đợi quy mô vừa.
- Đổi lại, kết quả trả về không còn nhất quán theo thứ tự đã yêu cầu: có worker sẽ nhận job mới hơn nếu job cũ đang bị giữ.
- Vẫn cần cột trạng thái và cơ chế thu hồi job của worker chết (started_at quá hạn thì trả về pending), vì khoá tự nhả khi kết nối đứt nhưng trạng thái running thì không tự đổi.