34.9. Асинхронное уведомление
PostgreSQL предлагает асинхронное уведомление посредством команд LISTEN
и NOTIFY
. Клиентский сеанс работы регистрирует свою заинтересованность в конкретном канале уведомлений с помощью команды LISTEN
(и может остановить прослушивание с помощью команды UNLISTEN
). Все сеансы, прослушивающие конкретный канал, будут уведомляться в асинхронном режиме, когда в рамках любого сеанса команда NOTIFY
выполняется с параметром, указывающим имя этого канала. Для передачи дополнительных данных прослушивающим сеансам может использоваться строка «payload».
Приложения, использующие libpq, отправляют серверу команды LISTEN
, UNLISTEN
и NOTIFY
как обычные SQL-команды. Поступление сообщений от команды NOTIFY
можно впоследствии отследить с помощью функции PQnotifies
.
Функция PQnotifies
возвращает следующее уведомление из списка необработанных уведомительных сообщений, полученных от сервера. Она возвращает нулевой указатель, если нет уведомлений, ожидающих обработки. Как только уведомление возвращено из функции PQnotifies
, оно считается обработанным и будет удалено из списка уведомлений.
PGnotify *PQnotifies(PGconn *conn); typedef struct pgNotify { char *relname; /* имя канала уведомлений */ int be_pid; /* ID серверного процесса, посылающего уведомление */ char *extra; /* строка сообщения в уведомлении */ } PGnotify;
После обработки объекта PGnotify
, возвращённого функцией PQnotifies
, обязательно освободите память, занимаемую им, с помощью функции PQfreemem
. Достаточно освободить указатель на PGnotify
; поля relname
и extra
не представляют отдельных областей памяти. (Имена этих полей являются таковыми по историческим причинам; в частности, имена каналов не обязаны иметь ничего общего с именами реляционных отношений.)
Пример 34.2 представляет пример программы, иллюстрирующей использование асинхронного уведомления.
Функция PQnotifies
в действительности не читает данные с сервера; она просто возвращает сообщения, предварительно собранные другой функцией библиотеки libpq. В очень старых выпусках libpq обеспечить своевременное получения сообщений от команды NOTIFY
можно было только одним способом — постоянно отправлять команды, пусть даже пустые, а затем проверять PQnotifies
после каждого вызова PQexec
. Хотя этот метод всё ещё работает, он считается устаревшим ввиду неэффективного использования процессора.
Более удачным способом проверки наличия сообщений от команды NOTIFY
, когда у вас нет полезных команд для выполнения, является вызов функции PQconsumeInput
с последующей проверкой PQnotifies
. Вы можете использовать select()
, чтобы подождать прибытия данных с сервера, не занимая тем самым ресурсы CPU в отсутствие задач для выполнения. (Получить номер дескриптора для использования с select()
можно с помощью функции PQsocket
.) Заметьте, что это будет работать независимо от того, отправляете ли вы команды, используя PQsendQuery
/PQgetResult
, или просто вызываете PQexec
. Однако важно не забывать проверять PQnotifies
после каждого вызова PQgetResult
или PQexec
, чтобы увидеть, не поступили ли какие-либо уведомления в процессе обработки команды.