PostgreSQL LISTEN/NOTIFY: оповестить приложение

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

LISTEN и NOTIFY — встроенный механизм уведомлений PostgreSQL: одна сессия подписывается на канал, другая отправляет сообщение с небольшим текстовым payload. Уведомления доставляются только после успешного COMMIT и не сохраняются на диске. Это удобно для мгновенного сигнала приложению, но не заменяет очередь задач.

Подписаться на канал и отправить сообщение

SQL
-- Сессия приложения: остаётся открытой и слушает канал
LISTEN order_created;

-- Другая сессия: отправляет уведомление после коммита
NOTIFY order_created, '{"id": 42}';

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

LISTEN действует в рамках сессии. В пуле соединений подписка может достаться другому запросу или потеряться при переподключении, поэтому держите отдельное долгоживущее соединение и восстанавливайте LISTEN после разрыва. Драйверы отдают уведомления через callback или асинхронный итератор: например, asyncpg использует add_listener(), а psycopg — connection.notifies().

Отправлять уведомление триггером

SQL
CREATE TABLE orders (
    id bigserial PRIMARY KEY,
    total numeric(10, 2) NOT NULL
);

CREATE OR REPLACE FUNCTION notify_order_created()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
    PERFORM pg_notify(
        'order_created',
        json_build_object('id', NEW.id, 'total', NEW.total)::text
    );
    RETURN NEW;
END;
$$;

CREATE TRIGGER orders_notify_after_insert
AFTER INSERT ON orders
FOR EACH ROW
EXECUTE FUNCTION notify_order_created();

INSERT INTO orders (total) VALUES (1990.00);

pg_notify() делает то же, что NOTIFY, но принимает имя канала и payload как обычные аргументы функции. Триггер срабатывает в той же транзакции, а уведомление уходит наружу только после её коммита. Если транзакция откатится, сообщение не будет доставлено.

Уведомления не гарантируют доставку: если приложение было отключено, сообщение пропадёт. Для надёжной обработки храните события в таблице и забирайте их через FOR UPDATE SKIP LOCKED, а NOTIFY используйте как сигнал «проверь таблицу». Не передавайте в payload секреты и большие JSON-документы: содержимое видно в логах и в подключённых сессиях.

Документация: NOTIFY, LISTEN, pg_notify.