Перейти к основному содержимому

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.

Смотрите также

LISTEN, UNLISTEN, max_notify_queue_pages