31.8. Асинхронное уведомление
Postgres Pro предлагает асинхронное уведомление посредством команд 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
не представляют отдельных областей памяти. (Имена этих полей являются таковыми по историческим причинам; в частности, имена каналов не обязаны иметь ничего общего с именами реляционных отношений.)
Пример 31.2 представляет пример программы, иллюстрирующей использование асинхронного уведомления.
Функция PQnotifies
в действительности не читает данные с сервера; она просто возвращает сообщения, предварительно собранные другой функцией библиотеки libpq. В очень старых выпусках libpq обеспечить своевременное получения сообщений от команды NOTIFY
можно было только одним способом — постоянно отправлять команды, пусть даже пустые, а затем проверять PQnotifies
после каждого вызова PQexec
. Хотя этот метод всё ещё работает, он считается устаревшим ввиду неэффективного использования процессора.
Более хорошим способом проверки наличия сообщений от команды NOTIFY
, когда у вас нет полезных команд для выполнения, является вызов функции PQconsumeInput
с последующей проверкой PQnotifies
. Вы можете использовать select()
, чтобы подождать прибытия данных с сервера, тем самым не используя мощности CPU, если нет полезной работы. (См. PQsocket
насчёт получения номера файлового дескриптора для использования его с select()
.) Обратите внимание, что это будет хорошо работать, независимо от того, отправляете ли вы команды с помощью PQsendQuery
/PQgetResult
или просто используете PQexec
. Следует, однако, не забывать проверять PQnotifies
после каждого вызова PQgetResult
или PQexec
, чтобы увидеть, не прибыли ли какие-либо уведомления в процессе обработки команды.