PostgreSQL SKIP LOCKED: разобрать очередь параллельно

Категория: Postgresql · Язык: SQL · Обновлено:

FOR UPDATE SKIP LOCKED позволяет нескольким обработчикам брать разные свободные строки очереди, не ожидая запись, которую уже захватил другой обработчик. Используйте его для короткой транзакции выдачи задачи, а не как общий способ читать согласованный набор данных: результат намеренно пропускает заблокированные строки.

Выдать одну задачу и пометить её занятой

Предполагается, что jobs содержит поля id, status, started_at и payload. Один UPDATE ... RETURNING атомарно выбирает доступную задачу и возвращает её вызывающему обработчику:

SQL
WITH next_job AS (
    SELECT id
    FROM jobs
    WHERE status = 'ready'
    ORDER BY id
    LIMIT 1
    FOR UPDATE SKIP LOCKED
)
UPDATE jobs AS job
SET status = 'running', started_at = now()
FROM next_job
WHERE job.id = next_job.id
RETURNING job.id, job.payload;

Если строка занята другим воркером, запрос возьмёт следующую; когда свободных задач нет, он вернёт ноль строк. Индекс по статусу и порядку обработки может помочь большой очереди, но подбирайте его по фактическому плану.

Держите транзакцию короткой: не выполняйте сетевую работу до фиксации захвата задачи. Добавьте срок аренды или отдельный механизм восстановления задач, оставшихся в running после сбоя воркера. Для пустой очереди обработчик должен спокойно дождаться следующей попытки.

Официальная справка: SELECT — locking clause.