PostgreSQL LISTEN/NOTIFY: оповестить приложение
LISTEN и NOTIFY — встроенный механизм уведомлений PostgreSQL: одна сессия подписывается на канал, другая отправляет сообщение с небольшим текстовым payload. Уведомления доставляются только после успешного COMMIT и не сохраняются на диске. Это удобно для мгновенного сигнала приложению, но не заменяет очередь задач.
Подписаться на канал и отправить сообщение
-- Сессия приложения: остаётся открытой и слушает канал
LISTEN order_created;
-- Другая сессия: отправляет уведомление после коммита
NOTIFY order_created, '{"id": 42}';Имя канала — идентификатор без кавычек или строка в кавычках. Payload передаётся как строка и ограничен примерно 8000 байтами. Если в одной транзакции отправить несколько одинаковых уведомлений на один канал, PostgreSQL может свернуть их в одно. Слушатель получает сообщение только после фиксации транзакции отправителя.
LISTEN действует в рамках сессии. В пуле соединений подписка может достаться другому запросу или потеряться при переподключении, поэтому держите отдельное долгоживущее соединение и восстанавливайте LISTEN после разрыва. Драйверы отдают уведомления через callback или асинхронный итератор: например, asyncpg использует add_listener(), а psycopg — connection.notifies().
Отправлять уведомление триггером
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.