Я хочу сделать постоянную очередь заданий в postgresql.Чтобы несколько работников могли выбрать одно задание из очереди (используя select for update
с skip locked
), обработать его и затем удалить из очереди.У меня есть таблица:
create table queue (
id serial primary key
some_job_param1 text not null
some_job_param2 text not null
)
Теперь, если есть две работы, то она работает нормально:
worker1
начинает транзакцию и выбирает первую работу
begin;
select * from queue for update skip locked limit 1;
начинает обработку.worker2
делает то же самое и выбирает второе задание с тем же запросом.
После того, как worker1
выполнит свою работу, удалит ее из очереди и подтвердит транзакцию:
delete from queue where id=$1;
commit;
Тогда worker1
готов к новой работе, поэтому он делает то же самое.Начинает новую транзакцию, выбирает для работы, которая не заблокирована.Но проблема в том, что больше нет заданий, запрос возвращает ноль строк.
Идеально было бы, если бы запрос блокировался до тех пор, пока не появится новое задание, и он вернет результат.Это как-то возможно?Или я иду в неправильном направлении?
РЕДАКТИРОВАТЬ:
рабочие являются внешним процессом.Таким образом, если работник умер, сеанс умирает, и транзакция также.Тогда выбранная работа больше не будет заблокирована и готова для другого работника.Псевдокод будет выглядеть так:
while (true) {
tx = db.new_transaction()
job_id, param1, param2 = tx.query("select * from queue for update skip locked limit 1")
try {
some_long_processing(param1, param2)
tx.commit()
} catch {
tx.rollback()
}
}