Comments 24
… корректно завершив соединение с клиентской стороны, можно избавиться от всех наложенных им блокировок.
На самом деле любое завершение соединения (в том числе некорректное) приводит к неявному вызову pg_advisory_unlock_all:
pg_advisory_unlock_all освобождает все блокировки на уровне сеанса, закреплённые за текущим сеансом. (Эта функция неявно вызывается в конце любого сеанса, даже при нештатном отключении клиента.)
… чтобы работать на этих данных мог всего лишь один процесс одновременно.
Как решаете проблему с перезагрузкой сервера после получения лока? Насколько я знаю, advisory locks не восстанавливаются после рестарта.
к pg_try_advisory_lock('queue_table'::regclass::oid
нужно дописать ::int
, иначе будет ошибка
SELECT
*
FROM
queue_table
WHERE
pg_try_advisory_lock('queue_table'::regclass::oid::int, pk_id)
ORDER BY
pk_id
LIMIT 1;
такая конструкция берет из таблицы одну строку, но блокирует все. Почему так?
Как правило, причина одна - нет полностью соответствующего индекса, и запрос уходит в Bitmap Heap Scan или Seq Scan.
нужен индекс
SET enable_seqscan TO off; SET enable_bitmapscan TO off;
дак у вас условие ГДЕ сначала блокирует все строки, а потом уже по ЛИМИТу возвращается одна из всех
Можно ещё так попробовать
with s as (select * from queue_table order by pk_id limit 1 for update of queue_table skip locked) update queue_table set ... returning ...
Если приложение переиспользует соединения к БД (connection pool), то возможна ситуация, когда несколько неких worker-ов получат доступ к одной и той же блокировке?
Если речь про pgbouncer, то в session mode - нет, каждому клиентскому подключению будет выдаваться свое серверное на все время. Если не забывать разблокировать свое - проблем не будет. В transaction mode - запросто при не-xact-функциях.
Речь про connection pool на стороне приложения. Предположим, что таски из очереди из примера обрабатывает одно приложение в несколько тредов. Причём количество обработчиков больше размера пула.
Фантастические advisory locks, и где они обитают