Ответ
NOTIFY
и LISTEN
в PostgreSQL — это асинхронный механизм межпроцессного взаимодействия, который позволяет реализовать паттерн "Издатель-подписчик" (Pub/Sub) на уровне базы данных.
Принцип работы:
- Подписчик (
LISTEN
): Один или несколько клиентов (сессий) подписываются на канал, выполняя командуLISTEN channel_name;
. - Издатель (
NOTIFY
): Другой клиент отправляет уведомление в этот канал с помощью командыNOTIFY channel_name, 'payload';
. Полезная нагрузка (payload
) — это опциональная строка. - Получение уведомления: Все подписчики асинхронно получают уведомление. Это не прерывает их текущие запросы.
Основные сценарии использования в бэкенде:
- Real-time обновления: Отправка сигналов веб-серверу (например, через WebSocket) об изменении данных для немедленного обновления UI у клиентов.
- Инвалидация кэша: При изменении данных в таблице можно отправить
NOTIFY
, чтобы сервисы, кэширующие эти данные, сбросили свой кэш. - Сигнализация для фоновых воркеров: Основное приложение может уведомить фоновый воркер о появлении новой задачи в очереди без необходимости постоянно опрашивать БД (
polling
).
Пример использования в Go (с библиотекой pgx
):
// Воркер, который слушает уведомления
go func() {
conn, _ := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
defer conn.Close(context.Background())
_, err := conn.Exec(context.Background(), "listen updates")
if err != nil { /* ... */ }
for {
notification, err := conn.WaitForNotification(context.Background())
if err != nil { /* ... */ }
fmt.Printf("PID: %d, Channel: %s, Payload: %sn",
notification.PID, notification.Channel, notification.Payload)
}
}()
// ... в другой части приложения, например, в HTTP-обработчике
// conn2 - другое соединение
_, err := conn2.Exec(context.Background(), "notify updates, 'user 123 updated' ")
Особенности и ограничения:
- Транзакционность: Уведомления отправляются только после успешного коммита транзакции, в которой был выполнен
NOTIFY
. - Нет гарантии доставки: Если клиент отключается, он теряет все уведомления, отправленные во время его отсутствия.
- Ограниченный размер
payload
: Полезная нагрузка не может превышать 8000 байт.