NOTIFY
Эта страница переведена при помощи нейросети GigaChat.
NOTIFY
- генерация уведомления.
Синтаксис
NOTIFY channel [ , payload ]
Описание
Команда NOTIFY
отправляет событие уведомления вместе с дополнительной строкой «сообщения» (payload
) всем клиентским приложениям, которые до этого выполнили в текущей базе данных LISTEN
канал с указанным именем канала. Уведомления видны всем пользователям.
NOTIFY
предоставляет простой механизм межпроцессного взаимодействия для группы процессов, использующих одну и ту же базу данных PostgreSQL. Вместе с уведомлением можно передать строку «сообщение» (payload
), а при необходимости можно построить более сложные механизмы, передавая структурированные данные через таблицы — от отправителя к слушателю.
Клиент получает при уведомлении следующую информацию:
- имя канала уведомления;
- PID серверного процесса, отправившего уведомление;
- строка
payload
(если не указана, передается пустая строка).
Проектировщик базы данных сам определяет, какие имена каналов использовать и что они означают. Обычно имя канала совпадает с именем таблицы, и событие NOTIFY
интерпретируется как: «Я изменил эту таблицу, проверь, что в ней нового». Однако это всего лишь соглашение — никакой прямой связи между каналами и таблицами команды NOTIFY
и LISTEN
не навязывают. Можно, например, использовать разные имена каналов для обозначения разных видов изменений одной и той же таблицы, или передавать детали различий через строку payload
.
Когда NOTIFY
используется для сигнализации об изменениях в таблице, полезной практикой является вызов NOTIFY
в теле триггера, срабатывающего при обновлении таблицы. Таким образом, уведомление отправляется автоматически, и разработчик приложения не может забыть это сделать.
Команда NOTIFY
взаимодействует с транзакциями следующим образом, если:
NOTIFY
вызывается внутри транзакции, уведомление не будет доставлено, пока транзакция не будет зафиксирована. Это логично, ведь если транзакция будет отменена (ROLLBACK
), все ее действия (включаяNOTIFY
) аннулируются.- сессия, которая слушает уведомления, получает сигнал во время выполнения транзакции, то уведомление не будет передано клиенту, пока транзакция не завершится (
commit
илиrollback
). Это сделано потому, что сервер не может «отозвать» уведомление, уже доставленное клиенту.
Поэтому приложения, использующие NOTIFY
для сигналов в реальном времени, должны стараться сохранять транзакции короткими.
Если в одной транзакции несколько раз вызывается NOTIFY
с одним и тем же каналом и одинаковым payload
, то будет доставлено только одно уведомление.
Если payload
различаются — уведомления будут все переданы отдельно.
Аналогично, уведомления из разных транзакций никогда не объединяются в одно. Кроме того все уведомления из одной транзакции доставляются в порядке отправки, и уведомления из разных транзакций доставляются в порядке фиксации этих транзакций.
Обычно клиент, выполняющий NOTIFY
, также слушает этот канал сам.
В таком случае он получит собственное уведомление — как и другие сессии. Это может привести к лишней работе, например, сессия будет перечитывать таблицу, которую только что сама изменила.
Чтобы избежать этого, можно сравнить PID процесса, отправившего уведомление (приходит вместе с ним), с PID своей сессии (доступен через libpq). Если они совпадают, это значит, что уведомление — «эхо» собственного действия, и его можно проигнорировать.
Параметры
channel
- Имя канала для передачи уведомления (любой идентификатор).
payload
- Строка «сообщения», которая будет передана вместе с уведомлением. Должна быть строковым литералом. В стандартной конфигурации ее длина должна быть меньше 8000 байт. Если нужно передать бинарные данные или большой объем информации — лучше сохранить их в таблице и передавать ключ записи.
Примечания
Существует очередь уведомлений, в которой хранятся уведомления, пока они не будут получены всеми слушающими сессиями. Если эта очередь переполнится, транзакции с NOTIFY
будут завершаться с ошибкой при COMMIT
. Размер очереди достаточно большой (обычно 8 ГБ), и этого хватает для большинства случаев. Однако очистка очереди невозможна, если сессия выполнила LISTEN
и затем вошла в долгую транзакцию.
Когда очередь заполнена более чем на половину, в лог файле появится предупреждение с указанием сессии, мешающей очистке.
В таком случае нужно завершить транзакцию этой сессии, чтобы освободить место в очереди.
Функция pg_notification_queue_usage
возвращает долю занятого пространства в очереди.
Транзакция, которая была выполнена NOTIFY
, не может быть подготовлена для двухфазного подтверждения.
pg_notify
Уведомление можно также отправить с помощью функции pg_notify(text, text)
. Первый аргумент — имя канала, второй — текст сообщения.
Эта функция удобнее, чем команда NOTIFY
, если требуется использовать динамические имена каналов или сообщения.
Примеры
Демонстрация процедуры ожидания/получения уведомления в psql:
LISTEN virtual;
NOTIFY virtual;
Asynchronous notification "virtual" received from server process with PID 8448.
NOTIFY virtual, 'This is the payload';
Asynchronous notification "virtual" with payload "This is the payload" received from server process with PID 8448.
LISTEN foo;
SELECT pg_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server process with PID 14728.
Совместимость
В стандарте SQL нет команды NOTIFY
.